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.
158 lines
5.5 KiB
TypeScript
158 lines
5.5 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import About from "./About";
|
|
|
|
/**
|
|
* Testes de caminhos-base de About: a entrada dos quatro cartões (Reveal, CSS) com atrasos crescentes, o
|
|
* feedback de toque e de mouse por classes (cv-press, cv-lift; cartões sem foco), o conteúdo e a coluna de
|
|
* apoio. Nada de animação em JavaScript: o movimento reduzido é tratado pelo CSS.
|
|
*/
|
|
|
|
jest.mock("@/public/edev.jpg", () => ({
|
|
__esModule: true,
|
|
default: { src: "/edev.jpg", width: 10, height: 10 },
|
|
}));
|
|
|
|
jest.mock("./Section", () => ({
|
|
Section: ({
|
|
children,
|
|
id,
|
|
title,
|
|
description,
|
|
aside,
|
|
}: {
|
|
children?: React.ReactNode;
|
|
id?: string;
|
|
title?: string;
|
|
description?: string;
|
|
aside?: React.ReactNode;
|
|
}) => (
|
|
<section id={id}>
|
|
<h2>{title}</h2>
|
|
<p data-testid="about-description">{description}</p>
|
|
{aside}
|
|
{children}
|
|
</section>
|
|
),
|
|
}));
|
|
|
|
jest.mock("./animations/DrawLine", () => ({ DrawLine: () => null }));
|
|
jest.mock("./animations/LazyRevealImage", () => ({
|
|
LazyRevealImage: ({ alt }: { alt: string }) => (
|
|
<span role="img" aria-label={alt} />
|
|
),
|
|
}));
|
|
|
|
describe("About", () => {
|
|
it("path: the four cards enter through Reveal -> same rise and duration, delays growing in steps", () => {
|
|
const { container } = render(<About />);
|
|
|
|
const reveals = [...container.querySelectorAll<HTMLElement>(".ds-reveal")];
|
|
// 3 etapas da história + o card do perfil (o cabeçalho da seção é um dublê, sem Reveal)
|
|
expect(reveals).toHaveLength(4);
|
|
expect(
|
|
reveals.map((element) => element.style.getPropertyValue("--reveal-y")),
|
|
).toEqual(["20px", "20px", "20px", "20px"]);
|
|
expect(
|
|
reveals.map((element) =>
|
|
element.style.getPropertyValue("--reveal-duration"),
|
|
),
|
|
).toEqual(["0.8s", "0.8s", "0.8s", "0.8s"]);
|
|
const delays = reveals.map((element) =>
|
|
Number.parseFloat(element.style.getPropertyValue("--reveal-delay")),
|
|
);
|
|
expect(delays).toEqual([0.08, 0.16, 0.24, 0.32]);
|
|
for (const element of reveals) {
|
|
expect(element.style.opacity).toBe("");
|
|
expect(element.style.transform).toBe("");
|
|
}
|
|
});
|
|
|
|
it("path: the four cards are not focus stops and use the CSS press feedback", () => {
|
|
const { container } = render(<About />);
|
|
|
|
const cards = container.querySelectorAll("article");
|
|
expect(cards).toHaveLength(4);
|
|
for (const card of cards) {
|
|
expect(card).not.toHaveAttribute("tabindex");
|
|
expect(card).toHaveClass("cv-press");
|
|
}
|
|
});
|
|
|
|
it("path: the three story cards lift on hover and press with CSS; the profile card presses only", () => {
|
|
const { container } = render(<About />);
|
|
|
|
const cards = [...container.querySelectorAll("article")];
|
|
expect(cards).toHaveLength(4);
|
|
for (const card of cards.slice(0, 3)) {
|
|
expect(card).toHaveClass("cv-press", "cv-lift");
|
|
}
|
|
expect(cards[3]).toHaveClass("cv-press");
|
|
});
|
|
|
|
it("path: the story, the profile points and the résumé link are all there", () => {
|
|
render(<About />);
|
|
|
|
expect(
|
|
screen.getByRole("heading", {
|
|
level: 3,
|
|
name: "Sem intermediários entre o pedido e o sistema",
|
|
}),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText("Solução do tamanho do seu problema"),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("link", { name: "Ver trajetória completa" }),
|
|
).toHaveAttribute("href", "/curriculo");
|
|
});
|
|
|
|
it("path: speaks in client benefits, with no technical jargon, and cites the Apolo Energia work", () => {
|
|
const { container } = render(<About />);
|
|
|
|
expect(container.textContent).not.toMatch(
|
|
/protocolos de baixo nível|operabilidade|camada física|sinal físico/i,
|
|
);
|
|
// a seção abre pela credencial, logo depois do nome
|
|
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
|
|
"Evandro Fonseca Junior",
|
|
);
|
|
expect(screen.getByTestId("about-description").textContent).toMatch(
|
|
/^Engenheiro da computação; desde 2022 desenvolvo aplicações web e mobile, APIs e integrações com dispositivos IoT para as rotinas internas da Apolo Energia\./,
|
|
);
|
|
// só o que o currículo sustenta: nada de "os sistemas internos e a IoT" da empresa inteira
|
|
expect(container.textContent).not.toMatch(
|
|
/os sistemas internos e a IoT da Apolo/,
|
|
);
|
|
// a frase da Apolo aparece uma só vez
|
|
expect(container.textContent?.match(/Apolo Energia/g)).toHaveLength(1);
|
|
});
|
|
|
|
it("path: the first story card does not reuse the name 'Como eu trabalho' of the process list in the offers section right before", () => {
|
|
const { container } = render(<About />);
|
|
|
|
expect(container.textContent).not.toMatch(/Como eu trabalho/);
|
|
expect(screen.getByText("Acompanhamento")).toBeInTheDocument();
|
|
});
|
|
|
|
it("path: 'contato direto', 'fala direto' and 'conversa comigo' no longer repeat in the section", () => {
|
|
const { container } = render(<About />);
|
|
|
|
expect(container.textContent).not.toMatch(
|
|
/contato direto|fala direto|falar direto|conversa comigo/i,
|
|
);
|
|
});
|
|
|
|
it("path: the location label stays on one line and the columns stretch to the same height", () => {
|
|
const { container } = render(<About />);
|
|
|
|
expect(screen.getByText(/Garuva, SC · Atendimento remoto/)).toHaveClass(
|
|
"whitespace-nowrap",
|
|
);
|
|
expect(container.querySelector(".ds-grid-2")).toHaveClass("items-stretch");
|
|
const story = container.querySelectorAll("article");
|
|
for (const card of Array.from(story).slice(0, 3)) {
|
|
expect(card).toHaveClass("flex-1");
|
|
}
|
|
});
|
|
});
|