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.
167 lines
5.2 KiB
TypeScript
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);
|
|
});
|
|
});
|