Files

128 lines
4.1 KiB
TypeScript

import { act, fireEvent, render, screen } from "@testing-library/react";
import { MOBILE_QUERY } from "@/lib/device";
import { getFeaturedProjects } from "@/lib/portfolio-data";
import { ProjectReel } from "./ProjectReel";
import { ShowcaseProvider, useShowcaseOpen } from "./ShowcaseProvider";
import { PINNED_QUERY } from "./useShowcaseMedia";
/*
* A vitrine fixa e a janela ampliada (código e CSS) chegam sob demanda: o módulo só é carregado quando alguém precisa
* dele. Aqui os módulos pesados são trocados por dublês que contam quantas vezes foram carregados, e o React.lazy é o
* de verdade (os outros testes de showcase o trocam por componentes síncronos). A fábrica de cada dublê roda uma vez
* por arquivo, na primeira importação: os testes seguem esta ordem (celular, janela ampliada, desktop) e a contagem
* acumula de um para o outro.
*/
const mockLoads = { pinned: 0, lightbox: 0 };
jest.mock("./PinnedReel", () => {
mockLoads.pinned += 1;
return {
__esModule: true,
default: ({ items }: { items: unknown[] }) => (
<div data-testid="pinned-reel">{items.length} projetos fixos</div>
),
};
});
jest.mock("./ProjectLightbox", () => {
mockLoads.lightbox += 1;
return {
ProjectLightbox: ({ index }: { index: number }) => (
<div role="dialog" aria-label="ampliado">
aberto:{index}
</div>
),
};
});
jest.mock("@/app/hooks/useReducedMotion", () => ({
useReducedMotion: () => false,
}));
const projects = getFeaturedProjects(null);
const originalMatchMedia = window.matchMedia;
function mockViewport({ phone }: { phone: boolean }) {
window.matchMedia = jest.fn().mockImplementation((query: string) => ({
matches:
(query === MOBILE_QUERY && phone) || (query === PINNED_QUERY && !phone),
media: query,
addEventListener() {},
removeEventListener() {},
}));
}
afterEach(() => {
window.matchMedia = originalMatchMedia;
});
function Opener() {
const open = useShowcaseOpen();
return (
<button type="button" onClick={() => open("sev-modaintima")}>
ampliar
</button>
);
}
describe("carregamento sob demanda", () => {
it("1. on a phone nothing heavy is loaded: the list is all there is, and the window waits for a click", async () => {
mockViewport({ phone: true });
render(
<ShowcaseProvider projects={projects}>
<ProjectReel />
</ShowcaseProvider>,
);
await act(async () => {
await Promise.resolve();
});
expect(mockLoads).toEqual({ pinned: 0, lightbox: 0 });
expect(screen.queryByTestId("pinned-reel")).toBeNull();
expect(
screen.getByRole("region", { name: "Projetos de clientes" }),
).toBeInTheDocument();
});
it("2. the enlarged window is loaded when a project is enlarged, and only then", async () => {
mockViewport({ phone: true });
render(
<ShowcaseProvider projects={projects}>
<Opener />
</ShowcaseProvider>,
);
expect(mockLoads.lightbox).toBe(0);
fireEvent.click(screen.getByRole("button", { name: "ampliar" }));
expect(
await screen.findByRole("dialog", { name: "ampliado" }),
).toBeInTheDocument();
expect(mockLoads.lightbox).toBe(1);
expect(mockLoads.pinned).toBe(0);
});
it("3. the pinned reel is loaded where it fits, holding the place with a block of the same height until it arrives", async () => {
mockViewport({ phone: false });
const { container } = render(
<ShowcaseProvider projects={projects}>
<ProjectReel />
</ShowcaseProvider>,
);
// enquanto o pacote chega: o bloco reservado (com a conta da altura), não uma página que encolhe
const hold = container.querySelector(".ds-reel-placeholder");
expect(hold).not.toBeNull();
expect(hold).toHaveAttribute("aria-hidden", "true");
expect((hold as HTMLElement).style.getPropertyValue("--reel-sum")).not.toBe(
"",
);
expect(screen.queryByTestId("pinned-reel")).toBeNull();
expect(await screen.findByTestId("pinned-reel")).toBeInTheDocument();
expect(mockLoads.pinned).toBe(1);
expect(container.querySelector(".ds-reel-placeholder")).toBeNull();
});
});