O botão das ofertas rola até o contato com o tipo marcado e não quebra mais as âncoras; ofertas com o que você recebe e primeiro passo, logo depois da vitrine; bloco de IA fora da home; cartão largo da SEV no hero do celular; separador da faixa de clientes só entre itens; favicon de 13 para 1,8 KB; pré-carregamento só no hover e nunca de /#... fora da home; X do menu e cabeçalho opaco; WhatsApp com "o case"; /ia com 3 passos e modelo de relatório ilustrativo; Sobre alinhado ao currículo; CSP Report-Only com os domínios do Ads.
111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
import {
|
|
getFeaturedProjects,
|
|
type PortfolioProjectView,
|
|
} from "@/lib/portfolio-data";
|
|
import { isClientProject } from "@/lib/proof";
|
|
import Projects from "./Projects";
|
|
|
|
// o Link do Next, trocado por um <a> que mostra o `prefetch` recebido: HoverPrefetchLink começa em false
|
|
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>
|
|
),
|
|
}));
|
|
|
|
jest.mock("./Section", () => ({
|
|
Section: ({ children, title }: { children: ReactNode; title: string }) => (
|
|
<section>
|
|
<h2>{title}</h2>
|
|
{children}
|
|
</section>
|
|
),
|
|
}));
|
|
|
|
const providerProjects = jest.fn();
|
|
|
|
jest.mock("./showcase/ShowcaseProvider", () => ({
|
|
ShowcaseProvider: ({
|
|
children,
|
|
projects,
|
|
}: {
|
|
children: ReactNode;
|
|
projects: PortfolioProjectView[];
|
|
}) => {
|
|
providerProjects(projects);
|
|
return <div data-testid="showcase-provider">{children}</div>;
|
|
},
|
|
}));
|
|
|
|
jest.mock("./showcase/ProjectReel", () => ({
|
|
ProjectReel: () => <div data-testid="project-reel" />,
|
|
}));
|
|
|
|
// A página entrega só os projetos de cliente; aqui usamos os reais do portfólio, com uma demo indisponível de propósito
|
|
const clientProjects: PortfolioProjectView[] = getFeaturedProjects(null)
|
|
.filter(isClientProject)
|
|
.map((project, index) => ({
|
|
...project,
|
|
demoAvailability: index === 0 ? ("unavailable" as const) : "available",
|
|
}));
|
|
|
|
describe("Projects", () => {
|
|
beforeEach(() => providerProjects.mockClear());
|
|
|
|
it("presents the client projects once, through the reel only", () => {
|
|
const { container } = render(<Projects projects={clientProjects} />);
|
|
|
|
expect(clientProjects.length).toBeGreaterThan(0);
|
|
expect(screen.getByTestId("project-reel")).toBeInTheDocument();
|
|
expect(providerProjects).toHaveBeenCalledWith(clientProjects);
|
|
// sem grade de cards: nem artigos, nem capas provisórias
|
|
expect(container.querySelector("article")).toBeNull();
|
|
expect(container.querySelector(".ds-cover, .ds-cover-fallback")).toBeNull();
|
|
expect(screen.queryByRole("heading", { level: 3 })).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("drops the availability badge, the code link and every GitHub link", () => {
|
|
const { container } = render(<Projects projects={clientProjects} />);
|
|
|
|
expect(
|
|
screen.queryByText(/Demo indisponível|indisponível na última/i),
|
|
).toBeNull();
|
|
expect(screen.queryByText(/Ver codigo|Ver código/i)).toBeNull();
|
|
expect(screen.queryByText(/Abrir projeto/i)).toBeNull();
|
|
for (const link of container.querySelectorAll("a")) {
|
|
expect(link.getAttribute("href") ?? "").not.toMatch(/github\.com/);
|
|
}
|
|
});
|
|
|
|
it("ends with a secondary link to all the cases", () => {
|
|
render(<Projects projects={clientProjects} />);
|
|
|
|
const link = screen.getByRole("link", { name: "Ver os cases" });
|
|
expect(link).toHaveAttribute("href", "/cases");
|
|
// secundário: contorno, sem o fundo verde-limão do contato
|
|
expect(link.className).toContain("border");
|
|
expect(link.className).not.toContain("bg-[var(--slash)]");
|
|
expect(screen.getAllByRole("link")).toEqual([link]);
|
|
});
|
|
|
|
it("pre-fetches /cases only when the visitor reaches the link, not when it comes into view", () => {
|
|
render(<Projects projects={clientProjects} />);
|
|
|
|
const link = screen.getByRole("link", { name: "Ver os cases" });
|
|
expect(link).toHaveAttribute("data-prefetch", "false");
|
|
fireEvent.mouseEnter(link);
|
|
expect(link).toHaveAttribute("data-prefetch", "null");
|
|
});
|
|
});
|