Files
portifolio-evandrodevbr/e2e/routes.spec.ts
T
Evandro Fonseca Junior 1a60795107 chore: testes de ponta a ponta no CI e limpeza do repositório
Job e2e separado no CI; testes de teclado, rolagem, sem JS, axe no celular e menu do celular; limites de metadados derivados do sitemap; sai @react-three/fiber e @react-three/drei; pastas de ferramentas (.augment, .kiro, .claude/settings.local.json) fora do Git.
2026-10-14 17:01:37 -03:00

96 lines
3.3 KiB
TypeScript

import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { DESKTOP, PHONE, sitemapPaths } from "./helpers";
/**
* (a) Todas as rotas do /sitemap.xml respondem 200, sem erro de console e sem rolagem horizontal, no computador
* (1440x900) e no celular (390x844).
* (b) O axe não acha violação serious ou critical em nenhuma delas, nos mesmos dois tamanhos.
* As rotas vêm do próprio sitemap: uma página nova entra no teste sozinha.
*/
const VIEWPORTS = [
{ name: "computador 1440x900", size: DESKTOP },
{ name: "celular 390x844", size: PHONE },
] as const;
for (const { name, size } of VIEWPORTS) {
test.describe(`rotas do sitemap, ${name}`, () => {
test.use({ viewport: size });
test("respondem 200, sem erro de console e sem rolagem horizontal", async ({
page,
request,
}) => {
const paths = await sitemapPaths(request);
expect(paths.length, "rotas no sitemap").toBeGreaterThan(10);
for (const path of paths) {
await test.step(path, async () => {
const problems: string[] = [];
const onConsole = (
message: import("@playwright/test").ConsoleMessage,
) => {
if (message.type() === "error")
problems.push(`console.error: ${message.text()}`);
};
const onPageError = (error: Error) =>
problems.push(`erro não tratado: ${error.message}`);
page.on("console", onConsole);
page.on("pageerror", onPageError);
const response = await page.goto(path, { waitUntil: "load" });
// dá tempo de a hidratação e das primeiras animações acontecerem (e de errarem)
await page.waitForTimeout(800);
page.off("console", onConsole);
page.off("pageerror", onPageError);
expect.soft(response?.status(), `${path}: status`).toBe(200);
expect.soft(problems, `${path}: console`).toEqual([]);
const overflow = await page.evaluate(
() =>
Math.max(
document.documentElement.scrollWidth,
document.body.scrollWidth,
) - document.documentElement.clientWidth,
);
expect
.soft(overflow, `${path}: px de rolagem horizontal`)
.toBeLessThanOrEqual(0);
});
}
});
});
}
for (const { name, size } of VIEWPORTS) {
test.describe(`acessibilidade (axe), ${name}`, () => {
test.use({ viewport: size });
test("nenhuma violação serious ou critical em nenhuma rota do sitemap", async ({
page,
request,
}) => {
const paths = await sitemapPaths(request);
for (const path of paths) {
await test.step(path, async () => {
await page.goto(path, { waitUntil: "load" });
await page.waitForTimeout(800);
const { violations } = await new AxeBuilder({ page }).analyze();
const serious = violations
.filter(
({ impact }) => impact === "serious" || impact === "critical",
)
.map(
({ id, impact, nodes }) =>
`${id} (${impact}): ${nodes.length} elemento(s), por exemplo ${nodes[0]?.target.join(" ")}`,
);
expect.soft(serious, `${path}: axe`).toEqual([]);
});
}
});
});
}