158 lines
6.2 KiB
TypeScript
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);
|
|
});
|
|
});
|