Files
portifolio-evandrodevbr/app/components/showcase/ShowcaseProvider.paths.test.tsx
T
Evandro Fonseca Junior 318a764190 perf(movimento): sem tela vazia, passagens em CSS e vitrine leve
Projetos sobem sobre o palco do hero e o celular tem hero de uma tela sem mergulho; passagens com animation-timeline em CSS, sem GSAP nem motion; troca da vitrine sem texto duplicado; moldura de celular só com pôster e scrub reencodado em 960 px (9,4 para 5,2 MB); 3D monta na primeira interação e para quando parado; transição entre páginas do mesmo segmento; foco em anel duplo; texto de 15 px no celular; código morto removido.
2026-10-14 14:15:50 -03:00

167 lines
5.2 KiB
TypeScript

import { fireEvent, render, screen } from "@testing-library/react";
import { getFeaturedProjects } from "@/lib/portfolio-data";
import {
type ShowcaseItem,
ShowcaseProvider,
useShowcaseItems,
useShowcaseOpen,
} from "./ShowcaseProvider";
/**
* Testes de caminhos-base de ShowcaseProvider (complemento de ShowcaseProvider.test.tsx). O provedor só guarda a
* lista da vitrine e qual projeto está ampliado: aqui, a janela aberta quando a lista muda, a troca de projeto
* com a janela já aberta e a estabilidade do que ele entrega (lista e função de abrir) entre renderizações.
* A janela ampliada é um dublê que só mostra o índice.
*/
jest.mock("./ProjectLightbox", () => ({
ProjectLightbox: ({
index,
items,
onClose,
}: {
index: number;
items: unknown[];
onClose: () => void;
}) => (
<div role="dialog" aria-label="ampliado">
aberto:{index} de {items.length}
<button type="button" onClick={onClose}>
fechar
</button>
</div>
),
}));
const projects = getFeaturedProjects(null);
const clientIds = ["sev-modaintima", "lavacao-047", "sc-plus", "as-servicos"];
const clients = projects.filter((project) => clientIds.includes(project.id));
function Opener({ id }: { id: string }) {
const open = useShowcaseOpen();
return (
<button type="button" onClick={() => open(id)}>
abrir {id}
</button>
);
}
describe("ShowcaseProvider: janela ampliada e mudança da lista", () => {
it("path: window open and its project leaves the list -> the window goes away", () => {
const { rerender } = render(
<ShowcaseProvider projects={clients}>
<Opener id="sc-plus" />
</ShowcaseProvider>,
);
fireEvent.click(screen.getByRole("button", { name: "abrir sc-plus" }));
expect(screen.getByRole("dialog")).toHaveTextContent("aberto:2 de 4");
rerender(
<ShowcaseProvider
projects={clients.filter((project) => project.id !== "sc-plus")}
>
<Opener id="sc-plus" />
</ShowcaseProvider>,
);
expect(screen.queryByRole("dialog")).toBeNull();
});
it("path: window open and another project is opened -> it moves to the new project, one window only", () => {
render(
<ShowcaseProvider projects={clients}>
<Opener id="sev-modaintima" />
<Opener id="as-servicos" />
</ShowcaseProvider>,
);
fireEvent.click(
screen.getByRole("button", { name: "abrir sev-modaintima" }),
);
expect(screen.getByRole("dialog")).toHaveTextContent("aberto:0 de 4");
fireEvent.click(screen.getByRole("button", { name: "abrir as-servicos" }));
expect(screen.getAllByRole("dialog")).toHaveLength(1);
expect(screen.getByRole("dialog")).toHaveTextContent("aberto:3 de 4");
});
it("path: a project outside the showcase is asked while another window is open -> no window is left", () => {
render(
<ShowcaseProvider projects={projects}>
<Opener id="sev-modaintima" />
<Opener id="reddit-explorer" />
</ShowcaseProvider>,
);
fireEvent.click(
screen.getByRole("button", { name: "abrir sev-modaintima" }),
);
fireEvent.click(
screen.getByRole("button", { name: "abrir reddit-explorer" }),
);
// o id desconhecido não acha posição na lista: a janela não mostra projeto nenhum
expect(screen.queryByRole("dialog")).toBeNull();
});
it("path: closed window -> reopening the same project works again", () => {
render(
<ShowcaseProvider projects={clients}>
<Opener id="lavacao-047" />
</ShowcaseProvider>,
);
fireEvent.click(screen.getByRole("button", { name: "abrir lavacao-047" }));
fireEvent.click(screen.getByRole("button", { name: "fechar" }));
expect(screen.queryByRole("dialog")).toBeNull();
fireEvent.click(screen.getByRole("button", { name: "abrir lavacao-047" }));
expect(screen.getByRole("dialog")).toHaveTextContent("aberto:1 de 4");
});
});
type Captured = {
items: ShowcaseItem[];
open: (id: string) => void;
};
function Probe({ onRender }: { onRender: (captured: Captured) => void }) {
onRender({ items: useShowcaseItems(), open: useShowcaseOpen() });
return null;
}
describe("ShowcaseProvider: o que entrega a quem está dentro", () => {
it("path: re-render with the same projects -> the same list and the same open function", () => {
const seen: Captured[] = [];
const tree = () => (
<ShowcaseProvider projects={clients}>
<Probe onRender={(captured) => seen.push(captured)} />
</ShowcaseProvider>
);
const { rerender } = render(tree());
rerender(tree());
expect(seen.length).toBeGreaterThan(1);
expect(seen[seen.length - 1].items).toBe(seen[0].items);
expect(seen[seen.length - 1].open).toBe(seen[0].open);
});
it("path: a different list of projects -> a new list of items", () => {
const seen: Captured[] = [];
const probe = <Probe onRender={(captured) => seen.push(captured)} />;
const { rerender } = render(
<ShowcaseProvider projects={clients}>{probe}</ShowcaseProvider>,
);
rerender(
<ShowcaseProvider projects={clients.slice(0, 2)}>
{probe}
</ShowcaseProvider>,
);
expect(seen[0].items).toHaveLength(4);
expect(seen[seen.length - 1].items).toHaveLength(2);
});
});