chore: dependências e teste de ponta a ponta
Saem gsap, motion, clsx e tailwind-merge; entram server-only, @playwright/test e @axe-core/playwright. Suíte e2e (rotas, axe, teclado, navegação, sem JS, rolagem) rodável com pnpm test:e2e contra BASE_URL.
This commit is contained in:
1 parent
318a764190
commit
7b633f0f4a
12 files changed
+459
-94
No files matched your search
@@ -0,0 +1,91 @@
|
||||
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.
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("acessibilidade (axe), computador", () => {
|
||||
test.use({ viewport: DESKTOP });
|
||||
|
||||
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([]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user