feat(cases): mídia no topo, títulos de busca curtos e CreativeWork

Case com mídia ao lado do título e play acessível; problema de cada cliente reescrito com base nos dados; serviços relacionados em 2 cards; FAQ antes do próximo passo e bloco 'Onde já apliquei isso'; Apolo citada em IoT e arquitetura. metaTitle até 43 caracteres e descrições até 155 com teste; JSON-LD CreativeWork; imagens de compartilhamento abaixo de 100 KB; 404 e robots corrigidos; server-only nos módulos com node:.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 14:15:25 -03:00
1 parent c9a0b80656
commit e80f73d075
52 files changed
+2593 -439

No files matched your search

@@ -0,0 +1,102 @@
import { render, screen } from "@testing-library/react";
import { getShowcaseAssets } from "@/lib/project-showcase";
import { CaseCoverLink } from "./CaseCoverLink";
import { getCaseMedia } from "./case-media";
/**
* Testes de caminhos-base de CaseCoverLink: sem captura (nada), com captura (link fora da leitura e do teclado,
* com a capa dentro), os valores padrão de `sizes`, `priority` e `prefetch`, e os valores dados.
*/
jest.mock("./case-media", () => ({ getCaseMedia: jest.fn() }));
jest.mock("next/link", () => ({
__esModule: true,
default: ({
children,
prefetch,
...props
}: { children?: React.ReactNode; prefetch?: boolean | null } & Record<
string,
unknown
>) => (
<a data-prefetch={String(prefetch)} {...props}>
{children}
</a>
),
}));
const mockedGetCaseMedia = jest.mocked(getCaseMedia);
const props = {
id: "sev-modaintima",
title: "SEV Moda Íntima",
demoUrl: "https://sevmodaintima.com.br",
};
afterEach(() => {
mockedGetCaseMedia.mockReset();
});
describe("CaseCoverLink", () => {
it("path: no desktop capture -> renders nothing, not even the link", () => {
mockedGetCaseMedia.mockReturnValue(undefined);
const { container } = render(<CaseCoverLink {...props} />);
expect(container).toBeEmptyDOMElement();
expect(mockedGetCaseMedia).toHaveBeenCalledWith(props.id, "desktop");
});
it("path: capture found -> a link to the case, out of reading order and tab order, around the cover", () => {
mockedGetCaseMedia.mockImplementation(getShowcaseAssets);
const { container } = render(<CaseCoverLink {...props} />);
const link = container.querySelector("a");
expect(link).toHaveAttribute("href", `/cases/${props.id}`);
expect(link).toHaveAttribute("aria-hidden", "true");
expect(link).toHaveAttribute("tabindex", "-1");
expect(link?.querySelector(".ds-bframe-url")).toHaveTextContent(
"sevmodaintima.com.br",
);
expect(
screen.getByAltText(`Captura de tela do site ${props.title}`),
).toBeInTheDocument();
});
it("path: sizes, priority and prefetch omitted -> default sizes, lazy image and the link's own prefetch", () => {
mockedGetCaseMedia.mockImplementation(getShowcaseAssets);
const { container } = render(<CaseCoverLink {...props} />);
const image = screen.getByAltText(`Captura de tela do site ${props.title}`);
expect(image).toHaveAttribute("sizes", "(min-width: 1024px) 560px, 100vw");
expect(image).toHaveAttribute("loading", "lazy");
expect(container.querySelector("a")).toHaveAttribute(
"data-prefetch",
"undefined",
);
});
it("path: sizes, priority and prefetch given -> all of them are used", () => {
mockedGetCaseMedia.mockImplementation(getShowcaseAssets);
const { container } = render(
<CaseCoverLink {...props} sizes="320px" priority prefetch={false} />,
);
const image = screen.getByAltText(`Captura de tela do site ${props.title}`);
expect(image).toHaveAttribute("sizes", "320px");
expect(image).not.toHaveAttribute("loading", "lazy");
expect(container.querySelector("a")).toHaveAttribute(
"data-prefetch",
"false",
);
});
it("path: no demo address -> the browser bar falls back to the project title", () => {
mockedGetCaseMedia.mockImplementation(getShowcaseAssets);
const { container } = render(
<CaseCoverLink id={props.id} title={props.title} demoUrl={null} />,
);
expect(container.querySelector(".ds-bframe-url")).toHaveTextContent(
props.title,
);
});
});