- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
|
|
import Hero from "./Hero";
|
|
|
|
let mockReducedMotion = false;
|
|
|
|
jest.mock("framer-motion", () => {
|
|
const React = require("react");
|
|
|
|
const motion = new Proxy(
|
|
{},
|
|
{
|
|
get: (_, tag: string) => {
|
|
const Component = ({
|
|
children,
|
|
initial,
|
|
animate,
|
|
whileHover,
|
|
whileTap,
|
|
...props
|
|
}: {
|
|
children?: ReactNode;
|
|
initial?: unknown;
|
|
animate?: unknown;
|
|
whileHover?: unknown;
|
|
whileTap?: unknown;
|
|
} & Record<string, unknown>) => {
|
|
const dataProps = {
|
|
...(initial !== undefined
|
|
? { "data-initial": JSON.stringify(initial) }
|
|
: {}),
|
|
...(animate !== undefined
|
|
? { "data-animate": JSON.stringify(animate) }
|
|
: {}),
|
|
...(whileHover !== undefined
|
|
? { "data-while-hover": JSON.stringify(whileHover) }
|
|
: {}),
|
|
...(whileTap !== undefined
|
|
? { "data-while-tap": JSON.stringify(whileTap) }
|
|
: {}),
|
|
};
|
|
|
|
return React.createElement(tag, { ...props, ...dataProps }, children);
|
|
};
|
|
Component.displayName = `motion.${tag}`;
|
|
return Component;
|
|
},
|
|
},
|
|
);
|
|
|
|
return {
|
|
AnimatePresence: ({ children }: { children: React.ReactNode }) => children,
|
|
motion,
|
|
useInView: () => true,
|
|
useReducedMotion: () => mockReducedMotion,
|
|
};
|
|
});
|
|
|
|
describe("Hero reduced motion", () => {
|
|
afterEach(() => {
|
|
mockReducedMotion = false;
|
|
});
|
|
|
|
it("removes hover/tap scale animations when reduced motion is enabled", () => {
|
|
mockReducedMotion = true;
|
|
|
|
const { container } = render(<Hero />);
|
|
|
|
const primaryAction = screen.getByText(/Iniciar projeto/i).closest("a");
|
|
const secondaryAction = screen.getByText(/Ver projetos/i).closest("a");
|
|
|
|
expect(primaryAction).not.toHaveAttribute("data-while-hover");
|
|
expect(primaryAction).not.toHaveAttribute("data-while-tap");
|
|
expect(secondaryAction).not.toHaveAttribute("data-while-hover");
|
|
expect(secondaryAction).not.toHaveAttribute("data-while-tap");
|
|
|
|
const rootMotionBlock = container.querySelector(
|
|
"div[data-initial][data-animate]",
|
|
);
|
|
expect(rootMotionBlock).toBeInTheDocument();
|
|
expect(rootMotionBlock?.getAttribute("data-initial")).toContain(
|
|
'"opacity":0',
|
|
);
|
|
expect(rootMotionBlock?.getAttribute("data-animate")).toContain(
|
|
'"opacity":1',
|
|
);
|
|
});
|
|
|
|
it("keeps essential hero content visible with reduced motion enabled", () => {
|
|
mockReducedMotion = true;
|
|
|
|
render(<Hero />);
|
|
|
|
expect(screen.getByLabelText("evandro.dev.br")).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText(/Available for selected builds/i),
|
|
).toBeInTheDocument();
|
|
expect(screen.getByText(/Execution Brief/i)).toBeInTheDocument();
|
|
});
|
|
});
|