Files

158 lines
6.2 KiB
TypeScript

import { render, screen } from "@testing-library/react";
import { setNavigation } from "@/__mocks__/next/navigation";
import { getCaseMedia } from "@/app/cases/_components/case-media";
import { type Device, getShowcaseAssets } from "@/lib/project-showcase";
import { getServicePage } from "@/lib/site-content";
import ServicePage from "./page";
/**
* Testes de caminhos-base da escolha da capa do topo em ServicePage (complemento de page.test.tsx), com as capturas
* gravadas controladas pelo teste (getCaseMedia trocado por um dublê que só "tem" o que o teste diz).
*
* A capa vale quando o serviço tem `heroCase` E existe captura gravada do aparelho pedido (heroCase.device); senão
* entra o `diagram` do serviço, se tiver; sem os dois, o topo vira uma coluna só e mais baixa.
* Caminhos: capa de computador | capa de celular | sem captura do computador | só captura do outro aparelho |
* case da capa que não existe | serviço de esquema, com ou sem captura de qualquer case.
* Quando a capa vale, a legenda dela cita o case e o case não ganha cartão em "Trabalhos parecidos".
*/
beforeEach(() => {
setNavigation({ pathname: "/servicos" });
});
jest.mock("@/app/cases/_components/case-media", () => ({
...jest.requireActual("@/app/cases/_components/case-media"),
getCaseMedia: jest.fn(),
}));
type Capture = readonly [id: string, device: Device];
/** Só as capturas listadas existem no disco. */
function capturesOnDisk(captures: readonly Capture[]) {
jest
.mocked(getCaseMedia)
.mockImplementation((id, device) =>
captures.some(
([knownId, knownDevice]) => knownId === id && knownDevice === device,
)
? getShowcaseAssets(id, device)
: undefined,
);
}
async function renderService(slug: string) {
const ui = await ServicePage({ params: Promise.resolve({ slug }) });
const view = render(ui);
const hero = view.container.querySelector("section") as HTMLElement;
return {
...view,
hero,
twoColumns: hero
.querySelector(".ds-section-shell")
?.classList.contains("grid"),
compact: hero.className.includes("md:!pb-sp-12"),
caption: hero.querySelector("figure figcaption"),
cards: Array.from(
view.container.querySelectorAll("#casos-relacionados article"),
).map((card) => card.querySelector(".ds-kicker")?.textContent),
};
}
afterEach(() => {
jest.mocked(getCaseMedia).mockReset();
});
describe("ServicePage: escolha da capa do topo", () => {
it("path: desktop cover with its capture on disk -> browser frame in the hero, the caption cites the case and the case gets no card", async () => {
capturesOnDisk([["lavacao-047", "desktop"]]);
const view = await renderService("criacao-de-sites");
expect(view.hero.querySelector(".ds-bframe")).not.toBeNull();
expect(view.twoColumns).toBe(true);
expect(view.compact).toBe(false);
expect(view.caption).toHaveTextContent("Lavação 047");
expect(view.cards).not.toContain("Lavação 047");
// a SEV é o segundo trabalho; SC Plus e AS Serviços ficam no bloco menor, fora de "Onde já apliquei isso"
expect(view.cards).toEqual(["SEV Moda Íntima"]);
});
it("path: mobile cover with its capture on disk -> phone frame in the hero, no browser frame", async () => {
capturesOnDisk([["sev-modaintima", "mobile"]]);
const view = await renderService("engenharia-de-software");
expect(view.hero.querySelector(".ds-phone-screen")).not.toBeNull();
expect(view.hero.querySelector(".ds-bframe")).toBeNull();
expect(view.twoColumns).toBe(true);
expect(view.caption).toHaveTextContent("SEV Moda Íntima");
expect(view.cards).toEqual(["Lavação 047"]);
});
it("path: no capture on disk -> no cover, a lower one-column hero, and the case that would be the cover gets its card back", async () => {
capturesOnDisk([]);
const view = await renderService("criacao-de-sites");
expect(view.hero.querySelector("figure")).toBeNull();
expect(view.twoColumns).toBe(false);
expect(view.compact).toBe(true);
expect(screen.queryByRole("img")).toBeNull();
expect(view.cards).toEqual(["Lavação 047", "SEV Moda Íntima"]);
});
it("path: only the OTHER device was captured (mobile cover, desktop capture) -> no cover, the check follows the device the service asks for", async () => {
capturesOnDisk([["sev-modaintima", "desktop"]]);
const view = await renderService("engenharia-de-software");
expect(view.hero.querySelector("figure")).toBeNull();
expect(view.compact).toBe(true);
expect(view.cards).toEqual(["SEV Moda Íntima", "Lavação 047"]);
expect(getCaseMedia).toHaveBeenCalledWith("sev-modaintima", "mobile");
});
it("path: the cover case does not exist -> same as no capture, no crash", async () => {
capturesOnDisk([["nao-existe", "desktop"]]);
const service = getServicePage("consultoria-nextjs");
if (!service?.heroCase) throw new Error("Missing hero case");
const original = service.heroCase;
service.heroCase = { id: "nao-existe", device: "desktop" };
try {
const view = await renderService("consultoria-nextjs");
expect(view.hero.querySelector("figure")).toBeNull();
expect(view.compact).toBe(true);
} finally {
service.heroCase = original;
}
});
it("path: diagram service -> the diagram, never a cover, even with every capture on disk", async () => {
capturesOnDisk([
["twins-lab", "desktop"],
["twins-lab", "mobile"],
["lavacao-047", "desktop"],
]);
const view = await renderService("integracao-hardware-software-iot");
expect(
screen.getByRole("img", { name: /dispositivo envia as leituras/ }),
).toBeVisible();
expect(view.hero.querySelector(".ds-bframe")).toBeNull();
expect(view.twoColumns).toBe(true);
expect(view.compact).toBe(false);
});
it("path: a service with a cover AND the capture missing never falls back to a diagram it does not have", async () => {
capturesOnDisk([]);
const service = getServicePage("consultoria-nextjs");
const view = await renderService("consultoria-nextjs");
expect(service?.diagram).toBeUndefined();
expect(screen.queryByRole("img", { name: /Esquema|esquema/ })).toBeNull();
expect(view.compact).toBe(true);
});
});