/servicos abre com as 3 ofertas e depois outros serviços; H1 de criação de sites e de engenharia com o nome da oferta; capa de cada serviço pelo assunto (SEV fora do próprio case cai de ~11 para 2 imagens); diagrama de fluxo em SVG nos serviços sem case; cases com o que o cliente passou a poder fazer e contato logo depois de Como ficou; FAQ num componente só; lastmod por rota; ProfessionalService com areaServed.
220 lines
7.9 KiB
TypeScript
220 lines
7.9 KiB
TypeScript
import { render, screen, within } from "@testing-library/react";
|
|
import { getCaseMedia } from "@/app/cases/_components/case-media";
|
|
import { getShowcaseAssets } from "@/lib/project-showcase";
|
|
import { caseStudies, isClientCase } from "@/lib/site-content";
|
|
import { ServiceRelatedCases } from "./ServiceRelatedCases";
|
|
|
|
/**
|
|
* Testes de caminhos-base de ServiceRelatedCases, direto no componente:
|
|
* sem case nem experiência, só a experiência, case sem frase de relação, case de laboratório,
|
|
* case sem captura e case sem site no ar. A existência dos arquivos em disco é simulada em getCaseMedia.
|
|
*/
|
|
|
|
jest.mock("@/app/cases/_components/case-media", () => ({
|
|
getCaseMedia: jest.fn(),
|
|
}));
|
|
|
|
const mockedGetCaseMedia = jest.mocked(getCaseMedia);
|
|
|
|
function getCase(id: string) {
|
|
const caseStudy = caseStudies.find((item) => item.id === id);
|
|
if (!caseStudy) throw new Error(`Missing case ${id}`);
|
|
return caseStudy;
|
|
}
|
|
|
|
function withDesktopCapture() {
|
|
mockedGetCaseMedia.mockImplementation((id, device) =>
|
|
device === "desktop" ? getShowcaseAssets(id, device) : undefined,
|
|
);
|
|
}
|
|
|
|
const sev = getCase("sev-modaintima"); // cliente, com site no ar
|
|
const asServicos = getCase("as-servicos"); // cliente, sem site público
|
|
const twins = getCase("twins-lab"); // laboratório, sem site público
|
|
/** Título com algum case de cliente; sem cliente (só experiência ou projeto próprio), é "Como eu trabalho nisso". */
|
|
const TITLE = "Onde já apliquei isso";
|
|
const TITLE_WITHOUT_CLIENT = "Como eu trabalho nisso";
|
|
const NOTE = "Texto de experiência de teste.";
|
|
|
|
beforeEach(() => {
|
|
mockedGetCaseMedia.mockReturnValue(undefined);
|
|
});
|
|
|
|
afterEach(() => {
|
|
mockedGetCaseMedia.mockReset();
|
|
});
|
|
|
|
describe("ServiceRelatedCases", () => {
|
|
it("path: no case and no experience note -> renders nothing", () => {
|
|
const { container } = render(
|
|
<ServiceRelatedCases cases={[]} relevance={{}} />,
|
|
);
|
|
|
|
expect(container).toBeEmptyDOMElement();
|
|
});
|
|
|
|
it("path: no case but an experience note -> keeps the block with the note and no case card", () => {
|
|
const { container } = render(
|
|
<ServiceRelatedCases cases={[]} relevance={{}} experienceNote={NOTE} />,
|
|
);
|
|
|
|
expect(
|
|
screen.getByRole("heading", { level: 2, name: TITLE_WITHOUT_CLIENT }),
|
|
).toBeVisible();
|
|
expect(screen.queryByRole("heading", { name: TITLE })).toBeNull();
|
|
expect(screen.getByText(NOTE)).toBeVisible();
|
|
expect(container.querySelectorAll("article")).toHaveLength(0);
|
|
expect(screen.queryByRole("link", { name: /^Ver case/ })).toBeNull();
|
|
});
|
|
|
|
it("path: cases and no experience note (main path) -> one card per case, no 'Na prática' paragraph", () => {
|
|
withDesktopCapture();
|
|
const { container } = render(
|
|
<ServiceRelatedCases
|
|
cases={[sev]}
|
|
relevance={{ [sev.id]: "Frase de relação do SEV." }}
|
|
/>,
|
|
);
|
|
|
|
expect(
|
|
screen.getByRole("heading", { level: 2, name: TITLE }),
|
|
).toBeVisible();
|
|
expect(screen.queryByText("Na prática:")).toBeNull();
|
|
const card = container.querySelector("article");
|
|
if (!card) throw new Error("Missing case card");
|
|
expect(within(card).getByText(sev.headline)).toBeVisible();
|
|
// case de cliente: o kicker é só o nome
|
|
const kicker = card.querySelector(".ds-kicker");
|
|
expect(kicker).toHaveTextContent(new RegExp(`^${sev.title}$`));
|
|
expect(within(card).queryByText(/Projeto próprio/)).toBeNull();
|
|
expect(within(card).getByText("Frase de relação do SEV.")).toBeVisible();
|
|
expect(
|
|
within(card).getByRole("link", { name: `Ver case ${sev.title}` }),
|
|
).toHaveAttribute("href", `/cases/${sev.id}`);
|
|
expect(
|
|
within(card).getByRole("link", { name: `Abrir o site ${sev.title}` }),
|
|
).toHaveAttribute("href", sev.demoUrl);
|
|
});
|
|
|
|
it("path: cases and an experience note -> the note comes first, in text only, with no link", () => {
|
|
render(
|
|
<ServiceRelatedCases
|
|
cases={[sev]}
|
|
relevance={{ [sev.id]: "Frase de relação do SEV." }}
|
|
experienceNote={NOTE}
|
|
/>,
|
|
);
|
|
|
|
const note = screen.getByText(NOTE, { exact: false });
|
|
expect(screen.getByText("Na prática:")).toBeVisible();
|
|
expect(note.closest("a")).toBeNull();
|
|
expect(note.querySelector("a")).toBeNull();
|
|
expect(
|
|
note.compareDocumentPosition(
|
|
screen.getByRole("link", { name: `Ver case ${sev.title}` }),
|
|
) & Node.DOCUMENT_POSITION_FOLLOWING,
|
|
).toBeTruthy();
|
|
});
|
|
|
|
it("path: case with a desktop capture -> cover link with the poster, hidden from assistive tech", () => {
|
|
withDesktopCapture();
|
|
const { container } = render(
|
|
<ServiceRelatedCases cases={[sev]} relevance={{ [sev.id]: "Frase." }} />,
|
|
);
|
|
|
|
const coverLink = container.querySelector(
|
|
`article a[aria-hidden="true"][href="/cases/${sev.id}"]`,
|
|
);
|
|
expect(coverLink).not.toBeNull();
|
|
expect(coverLink).toHaveAttribute("tabindex", "-1");
|
|
expect(coverLink?.querySelector(".ds-bframe img")).toHaveAttribute(
|
|
"alt",
|
|
`Captura de tela do site ${sev.title}`,
|
|
);
|
|
});
|
|
|
|
it("path: case without a desktop capture -> no cover link, text and buttons stay", () => {
|
|
const { container } = render(
|
|
<ServiceRelatedCases cases={[sev]} relevance={{ [sev.id]: "Frase." }} />,
|
|
);
|
|
|
|
expect(container.querySelector("a[aria-hidden='true']")).toBeNull();
|
|
expect(container.querySelector(".ds-bframe")).toBeNull();
|
|
expect(container.querySelector("img")).toBeNull();
|
|
expect(
|
|
screen.getByRole("link", { name: `Ver case ${sev.title}` }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
it("path: laboratory case -> kicker marks it as 'Projeto próprio'", () => {
|
|
expect(isClientCase(twins)).toBe(false);
|
|
render(
|
|
<ServiceRelatedCases
|
|
cases={[twins]}
|
|
relevance={{ [twins.id]: "Frase." }}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByText(`${twins.title} · Projeto próprio`)).toBeVisible();
|
|
// só projeto próprio, sem cliente: o título não promete trabalho aplicado para alguém
|
|
expect(
|
|
screen.getByRole("heading", { level: 2, name: TITLE_WITHOUT_CLIENT }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
it("path: case whose cover already opens the page -> it gets no card at all (the cover caption cites it), the others keep theirs", () => {
|
|
withDesktopCapture();
|
|
const lavacao = getCase("lavacao-047");
|
|
const { container } = render(
|
|
<ServiceRelatedCases
|
|
cases={[lavacao, sev]}
|
|
relevance={{}}
|
|
heroCaseId={lavacao.id}
|
|
/>,
|
|
);
|
|
|
|
expect(container.querySelectorAll("article")).toHaveLength(1);
|
|
expect(
|
|
container.querySelector(`a[href="/cases/${lavacao.id}"]`),
|
|
).toBeNull();
|
|
expect(container.textContent).not.toContain(lavacao.title);
|
|
expect(
|
|
container.querySelector(`a[aria-hidden="true"][href="/cases/${sev.id}"]`),
|
|
).not.toBeNull();
|
|
expect(
|
|
screen.getByRole("link", { name: `Ver case ${sev.title}` }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
it("path: the cover case is the only one -> no cases to list and no experience note -> renders nothing", () => {
|
|
const { container } = render(
|
|
<ServiceRelatedCases cases={[sev]} relevance={{}} heroCaseId={sev.id} />,
|
|
);
|
|
|
|
expect(container).toBeEmptyDOMElement();
|
|
});
|
|
|
|
it("path: no relevance sentence for the case -> falls back to the case summary", () => {
|
|
render(<ServiceRelatedCases cases={[sev]} relevance={{}} />);
|
|
|
|
const card = screen.getByRole("heading", { level: 3 }).closest("article");
|
|
expect(card).not.toBeNull();
|
|
expect(within(card as HTMLElement).getByText(sev.summary)).toBeVisible();
|
|
});
|
|
|
|
it("path: case without a public site -> no 'Abrir o site' link", () => {
|
|
expect(asServicos.demoUrl).toBeNull();
|
|
render(
|
|
<ServiceRelatedCases
|
|
cases={[asServicos]}
|
|
relevance={{ [asServicos.id]: "Frase." }}
|
|
/>,
|
|
);
|
|
|
|
expect(
|
|
screen.getByRole("link", { name: `Ver case ${asServicos.title}` }),
|
|
).toBeVisible();
|
|
expect(screen.queryByRole("link", { name: /^Abrir o site/ })).toBeNull();
|
|
});
|
|
});
|