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,72 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { DESKTOP } from "./helpers";
|
||||
|
||||
/**
|
||||
* (f) No computador, nenhuma das paradas a cada 10 % da rolagem da home tem tela vazia: sempre há ao menos um
|
||||
* elemento de texto visível na janela. Cabeçalho, avisos, leitores de tela e itens ocultos não contam
|
||||
* (o cabeçalho fixo estaria em todas as paradas e esconderia uma tela vazia).
|
||||
*/
|
||||
|
||||
test.use({ viewport: DESKTOP });
|
||||
|
||||
test("nenhuma parada a cada 10 % da home tem tela vazia", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "load" });
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
const empty: string[] = [];
|
||||
const stops: string[] = [];
|
||||
for (let step = 0; step <= 10; step++) {
|
||||
await page.evaluate((fraction) => {
|
||||
const max = document.documentElement.scrollHeight - innerHeight;
|
||||
window.scrollTo({ top: Math.round(max * fraction), behavior: "instant" });
|
||||
}, step / 10);
|
||||
// a rolagem suave, as animações ligadas à rolagem e as imagens preguiçosas assentam
|
||||
await page.waitForTimeout(700);
|
||||
|
||||
const result = await page.evaluate(() => {
|
||||
const ignored =
|
||||
"header, footer [aria-hidden], [aria-hidden='true'], [role='dialog'], .sr-only, .skip-link, script, style, noscript";
|
||||
const effectiveOpacity = (element: Element | null) => {
|
||||
let opacity = 1;
|
||||
for (let node = element; node; node = node.parentElement)
|
||||
opacity *= Number.parseFloat(getComputedStyle(node).opacity);
|
||||
return opacity;
|
||||
};
|
||||
const visible: string[] = [];
|
||||
const walker = document.createTreeWalker(
|
||||
document.body,
|
||||
NodeFilter.SHOW_TEXT,
|
||||
);
|
||||
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
||||
const text = node.textContent?.trim() ?? "";
|
||||
const parent = node.parentElement;
|
||||
if (text.length < 3 || !parent || parent.closest(ignored)) continue;
|
||||
const style = getComputedStyle(parent);
|
||||
if (style.visibility !== "visible" || style.display === "none")
|
||||
continue;
|
||||
if (effectiveOpacity(parent) < 0.2) continue;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(node);
|
||||
const rect = range.getBoundingClientRect();
|
||||
const inside =
|
||||
rect.width > 1 &&
|
||||
rect.height > 1 &&
|
||||
rect.bottom > 0 &&
|
||||
rect.top < innerHeight &&
|
||||
rect.right > 0 &&
|
||||
rect.left < innerWidth;
|
||||
if (inside) visible.push(text.slice(0, 40));
|
||||
}
|
||||
return { count: visible.length, sample: visible.slice(0, 2) };
|
||||
});
|
||||
|
||||
const label = `${step * 10}%`;
|
||||
stops.push(`${label}: ${result.count} trecho(s) de texto`);
|
||||
if (result.count === 0) empty.push(label);
|
||||
}
|
||||
|
||||
expect(
|
||||
empty,
|
||||
`paradas com tela vazia (nenhum texto visível):\n${stops.join("\n")}`,
|
||||
).toEqual([]);
|
||||
});
|
||||
Reference in new issue
Block a user