import { getCaseMedia } from "@/app/cases/_components/case-media"; import { getShowcaseAssets } from "@/lib/project-showcase"; import { getServicePage, type ServicePageContent } from "@/lib/site-content"; import { resolveServiceHero, splitServiceCases } from "./service-page"; /** * resolveServiceHero (CC 6): capa com captura | sem captura do aparelho pedido; esquema | sem esquema; o aparelho padrão * (computador) | o do serviço (celular); algum case com cartão | só o da capa | nenhum. * splitServiceCases (CC 3): serviço com bloco menor | sem ele; ids do bloco que o serviço relaciona | que não relaciona. * A existência das capturas em disco é simulada em getCaseMedia. */ jest.mock("@/app/cases/_components/case-media", () => ({ getCaseMedia: jest.fn(), })); const mockedGetCaseMedia = jest.mocked(getCaseMedia); function service(slug: string): ServicePageContent { const found = getServicePage(slug); if (!found) throw new Error(`Missing service ${slug}`); return found; } /** Só as capturas listadas existem no disco. */ function capturesOnDisk(captures: readonly (readonly [string, string])[]) { mockedGetCaseMedia.mockImplementation((id, device) => captures.some( ([knownId, knownDevice]) => knownId === id && knownDevice === device, ) ? getShowcaseAssets(id, device) : undefined, ); } afterEach(() => { mockedGetCaseMedia.mockReset(); }); describe("resolveServiceHero", () => { it("path: cover with its capture on disk -> the case is the cover, no diagram, two columns", () => { capturesOnDisk([["lavacao-047", "desktop"]]); const hero = resolveServiceHero(service("criacao-de-sites")); expect(hero.heroCase?.id).toBe("lavacao-047"); expect(hero.heroDevice).toBe("desktop"); expect(hero.diagram).toBeUndefined(); expect(hero.hasHeroSide).toBe(true); // a SEV, que não é a capa, ganha cartão expect(hero.hasCaseCards).toBe(true); }); it("path: a service that asks for the phone -> the capture is checked for the phone", () => { capturesOnDisk([["sev-modaintima", "mobile"]]); const hero = resolveServiceHero(service("engenharia-de-software")); expect(hero.heroDevice).toBe("mobile"); expect(hero.heroCase?.id).toBe("sev-modaintima"); expect(mockedGetCaseMedia).toHaveBeenCalledWith("sev-modaintima", "mobile"); }); it("path: cover without a capture and no diagram -> no side column, and the case that would be the cover gets its card back", () => { capturesOnDisk([]); const hero = resolveServiceHero(service("criacao-de-sites")); expect(hero.heroCase).toBeUndefined(); expect(hero.diagram).toBeUndefined(); expect(hero.hasHeroSide).toBe(false); expect(hero.hasCaseCards).toBe(true); }); it("path: service with a diagram -> the diagram fills the side column, desktop by default", () => { capturesOnDisk([]); const hero = resolveServiceHero(service("tauri-rust")); expect(hero.heroCase).toBeUndefined(); expect(hero.heroDevice).toBe("desktop"); expect(hero.diagram).toBe("desktop"); expect(hero.hasHeroSide).toBe(true); expect(hero.hasCaseCards).toBe(true); }); it("path: the only related case is the cover -> no card, so no 'Ver projetos parecidos' target", () => { capturesOnDisk([["sc-plus", "desktop"]]); const onlyCover: ServicePageContent = { ...service("consultoria-nextjs"), relatedCaseIds: ["sc-plus"], }; const hero = resolveServiceHero(onlyCover); expect(hero.heroCase?.id).toBe("sc-plus"); expect(hero.hasCaseCards).toBe(false); }); it("path: no related case at all -> no cards", () => { capturesOnDisk([]); expect(resolveServiceHero(service("arquitetura-de-software"))).toEqual({ heroCase: undefined, heroDevice: "desktop", diagram: "arquitetura", hasHeroSide: true, hasCaseCards: false, }); }); }); describe("splitServiceCases", () => { it("path: service with a smaller block -> the sites institucionais leave the cards and go to the block", () => { const { cards, also } = splitServiceCases(service("criacao-de-sites")); expect(cards.map(({ id }) => id)).toEqual([ "lavacao-047", "sev-modaintima", ]); expect(also?.title).toBe("Também faço sites institucionais"); expect(also?.cases.map(({ id }) => id)).toEqual(["sc-plus", "as-servicos"]); }); it("path: service without a smaller block -> every related case is a card and `also` is null", () => { const { cards, also } = splitServiceCases( service("engenharia-de-software"), ); expect(cards.map(({ id }) => id)).toEqual([ "sev-modaintima", "lavacao-047", ]); expect(also).toBeNull(); }); it("path: block ids that the service does not relate -> ignored, and with none left the block is null", () => { const stray: ServicePageContent = { ...service("consultoria-nextjs"), alsoCases: { title: "Também", caseIds: ["as-servicos", "nao-existe"] }, }; const { cards, also } = splitServiceCases(stray); expect(cards.map(({ id }) => id)).toEqual(["sc-plus", "lavacao-047"]); expect(also).toBeNull(); }); });