feat: add randomized portfolio hero variants
This commit is contained in:
1 parent
812499b318
commit
9236fdd685
25 files changed
+1438
-658
No files matched your search
@@ -1,9 +1,15 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import Hero from "./Hero";
|
||||
|
||||
let mockReducedMotion = false;
|
||||
jest.mock("next/dynamic", () => () => {
|
||||
const DynamicComponent = ({ variant }: { variant?: string }) => (
|
||||
<div data-testid="hero-scene" data-variant={variant} />
|
||||
);
|
||||
DynamicComponent.displayName = "MockHeroScene";
|
||||
return DynamicComponent;
|
||||
});
|
||||
|
||||
jest.mock("framer-motion", () => {
|
||||
const React = require("react");
|
||||
@@ -16,15 +22,15 @@ jest.mock("framer-motion", () => {
|
||||
children,
|
||||
initial,
|
||||
animate,
|
||||
whileHover,
|
||||
whileTap,
|
||||
whileHover: _whileHover,
|
||||
whileTap: _whileTap,
|
||||
variants: _variants,
|
||||
transition: _transition,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
initial?: unknown;
|
||||
animate?: unknown;
|
||||
whileHover?: unknown;
|
||||
whileTap?: unknown;
|
||||
} & Record<string, unknown>) => {
|
||||
const dataProps = {
|
||||
...(initial !== undefined
|
||||
@@ -33,12 +39,6 @@ jest.mock("framer-motion", () => {
|
||||
...(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);
|
||||
@@ -53,49 +53,67 @@ jest.mock("framer-motion", () => {
|
||||
AnimatePresence: ({ children }: { children: React.ReactNode }) => children,
|
||||
motion,
|
||||
useInView: () => true,
|
||||
useReducedMotion: () => mockReducedMotion,
|
||||
useReducedMotion: () => true,
|
||||
};
|
||||
});
|
||||
|
||||
function mockMatchMedia(matches: boolean) {
|
||||
Object.defineProperty(window, "matchMedia", {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
describe("Hero reduced motion", () => {
|
||||
afterEach(() => {
|
||||
mockReducedMotion = false;
|
||||
beforeEach(() => {
|
||||
mockMatchMedia(true);
|
||||
jest.spyOn(Math, "random").mockReturnValue(0);
|
||||
});
|
||||
|
||||
it("removes hover/tap scale animations when reduced motion is enabled", () => {
|
||||
mockReducedMotion = true;
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("keeps essential hero content visible with reduced motion enabled", async () => {
|
||||
render(<Hero />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByTestId("hero-scene")).not.toBeInTheDocument(),
|
||||
);
|
||||
|
||||
expect(screen.getByText(/Command center online/i)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("heading", {
|
||||
level: 1,
|
||||
name: /coloque seu sistema no ar/i,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("button", { name: /botar meu sistema no ar/i }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps motion blocks declarative instead of requiring 3D", async () => {
|
||||
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");
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByTestId("hero-scene")).not.toBeInTheDocument(),
|
||||
);
|
||||
|
||||
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();
|
||||
expect(rootMotionBlock?.getAttribute("data-initial")).toContain("hidden");
|
||||
expect(rootMotionBlock?.getAttribute("data-animate")).toContain("visible");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user