feat: add randomized portfolio hero variants

This commit is contained in:
Evandro Fonseca Junior committed 2026-07-10 02:46:42 -03:00
1 parent 812499b318
commit 9236fdd685
25 files changed
+1438 -658

No files matched your search

+60 -42
View File
@@ -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");
});
});