81 lines
2.9 KiB
TypeScript
81 lines
2.9 KiB
TypeScript
import { render, screen, waitFor } from "@testing-library/react";
|
|
import ScrollStory from "./ScrollStory";
|
|
|
|
// gsap é carregado via import() dinâmico dentro do effect; o contrato testado
|
|
// aqui é markup do reel (cenas/HUD/alvos), não a timeline — que é verificada
|
|
// no browser via probe CDP. Mock leve mantém a suíte em jsdom.
|
|
jest.mock("gsap", () => {
|
|
const chain = { set: jest.fn(), fromTo: jest.fn(), to: jest.fn() };
|
|
Object.assign(chain, {
|
|
set: jest.fn(() => chain),
|
|
fromTo: jest.fn(() => chain),
|
|
to: jest.fn(() => chain),
|
|
});
|
|
return {
|
|
gsap: {
|
|
registerPlugin: jest.fn(),
|
|
set: jest.fn(),
|
|
timeline: jest.fn(() => chain),
|
|
ticker: { add: jest.fn(), remove: jest.fn(), lagSmoothing: jest.fn() },
|
|
utils: { toArray: jest.fn(() => []) },
|
|
context: jest.fn((fn: () => void) => {
|
|
fn();
|
|
return { revert: jest.fn() };
|
|
}),
|
|
},
|
|
};
|
|
});
|
|
jest.mock("gsap/ScrollTrigger", () => ({
|
|
ScrollTrigger: { getAll: jest.fn(() => []) },
|
|
}));
|
|
|
|
const props = { projectsCount: 5, experiencesCount: 6, skillsCount: 18 };
|
|
|
|
function mockMatchMedia(matches: boolean) {
|
|
Object.defineProperty(window, "matchMedia", {
|
|
writable: true,
|
|
value: jest.fn().mockImplementation((query: string) => ({
|
|
matches,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: jest.fn(),
|
|
removeListener: jest.fn(),
|
|
addEventListener: jest.fn(),
|
|
removeEventListener: jest.fn(),
|
|
dispatchEvent: jest.fn(),
|
|
})),
|
|
});
|
|
}
|
|
|
|
describe("ScrollStory", () => {
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
mockMatchMedia(false);
|
|
});
|
|
|
|
it("renderiza fallback empilhado com conteúdo real com reduced motion", () => {
|
|
mockMatchMedia(true);
|
|
const { container } = render(<ScrollStory {...props} />);
|
|
// sem palco scrub: capítulos legíveis no fluxo, números reais do portfólio
|
|
expect(container.querySelector("[data-story]")).not.toBeInTheDocument();
|
|
expect(container).toHaveTextContent("01 — Visão geral");
|
|
expect(container).toHaveTextContent("04 — Próximo ciclo");
|
|
expect(container).toHaveTextContent("5");
|
|
expect(screen.getAllByText(/sistemas ativos no portfólio/)).toHaveLength(1);
|
|
});
|
|
|
|
it("renderiza o reel com 4 cenas, HUD e índice quando o engine liga", async () => {
|
|
const { container } = render(<ScrollStory {...props} />);
|
|
await waitFor(
|
|
() => expect(container.querySelector("[data-story]")).toBeInTheDocument(),
|
|
{ timeout: 10000 },
|
|
);
|
|
expect(container.querySelectorAll("[data-story-scene]")).toHaveLength(4);
|
|
expect(container.querySelector("[data-story-index]")).toHaveTextContent("01");
|
|
expect(container.querySelector("[data-story-bar]")).toBeInTheDocument();
|
|
// count-up é alimentado pela timeline: markup carrega o alvo real
|
|
const num = container.querySelector("[data-story-num]");
|
|
expect(num?.getAttribute("data-story-num-to")).toBe("5");
|
|
}, 20000);
|
|
});
|