test(e2e): fluxos de contato, navegação, teclado e menu do celular mais rígidos
CI / verify (push) Failing after 7m13s
CI / e2e (push) Failing after 7m1s

This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 22:54:27 -03:00
1 parent 8903f3c57e
commit 02298779df
8 files changed
+321 -115

No files matched your search

+88 -2
View File
@@ -1,14 +1,18 @@
import { expect, test } from "@playwright/test";
import { DESKTOP } from "./helpers";
import { DESKTOP_USE, PHONE_USE } from "./helpers";
/**
* (d) Clicar em "Cases" no menu e depois num case navega sem recarregar o documento (um marcador em `window`
* sobrevive) e cada troca de página dispara uma startViewTransition; a carga inicial, nenhuma.
* (k) De uma página rolada para outra (/servicos -> /servicos/criacao-de-sites, /cases -> um case), a página nova abre em
* scrollY === 0, sem animação: a cada quadro, a partir do clique, nunca se vê a página nova numa altura diferente de
* 0 (o `data-scroll-behavior` do <html> faz o Next desligar a rolagem suave só durante a troca de rota). No
* computador com clique, no celular (`isMobile`, `hasTouch`) com toque.
*/
type Probe = { __marker?: string; __viewTransitions?: number };
test.use({ viewport: DESKTOP });
test.use(DESKTOP_USE);
test("menu Cases e depois um case: sem recarregar o documento, uma transição de página por navegação", async ({
page,
@@ -61,3 +65,85 @@ test("menu Cases e depois um case: sem recarregar o documento, uma transição d
"o documento foi recarregado (o marcador sumiu)",
).toBe("mesmo-documento");
});
const SCROLLED_NAVIGATIONS = [
{
from: "/servicos",
link: "a[href='/servicos/criacao-de-sites']",
to: /\/servicos\/criacao-de-sites$/,
},
{ from: "/cases", link: "a[href^='/cases/']", to: /\/cases\/[^/]+$/ },
] as const;
const DEVICES = [
{ name: "computador, clique", use: DESKTOP_USE, tap: false },
{ name: "celular, toque", use: PHONE_USE, tap: true },
] as const;
for (const { name, use, tap } of DEVICES) {
test.describe(`página nova abre no topo, ${name}`, () => {
test.use(use);
for (const { from, link, to } of SCROLLED_NAVIGATIONS) {
test(`${from} rolado -> próxima página: scrollY 0 em todos os quadros, sem deslizar`, async ({
page,
}) => {
await page.goto(from, { waitUntil: "load" });
await page.waitForTimeout(1500);
const target = page.locator(link).first();
await target.scrollIntoViewIfNeeded();
await page.evaluate(() => {
const maxScroll = document.documentElement.scrollHeight - innerHeight;
window.scrollTo({
top: Math.min(1200, maxScroll),
behavior: "instant",
});
});
await page.waitForTimeout(300);
const before = await page.evaluate(() => Math.round(scrollY));
expect(before, `${from}: a página começa rolada`).toBeGreaterThan(300);
await expect(target).toBeVisible();
// a cada quadro desenhado, o caminho e a rolagem que a pessoa vê, até a nova página assentar
await page.evaluate(() => {
const frames: Array<{ path: string; y: number }> = [];
(window as unknown as { __frames: typeof frames }).__frames = frames;
const startedAt = performance.now();
const sample = () => {
frames.push({ path: location.pathname, y: Math.round(scrollY) });
if (performance.now() - startedAt < 4_000)
requestAnimationFrame(sample);
};
requestAnimationFrame(sample);
});
if (tap) await target.tap();
else await target.click();
await page.waitForURL(to);
await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
await page.waitForTimeout(4_200);
const { frames, finalY, path } = await page.evaluate(() => ({
frames: (
window as unknown as {
__frames: Array<{ path: string; y: number }>;
}
).__frames,
finalY: Math.round(scrollY),
path: location.pathname,
}));
const onNewPage = frames.filter((frame) => frame.path === path);
expect(
onNewPage.length,
"quadros vistos na página nova",
).toBeGreaterThan(5);
const notAtTop = onNewPage.filter((frame) => frame.y !== 0);
expect(
notAtTop.slice(0, 8),
`a página nova (${path}) foi vista fora do topo em ${notAtTop.length} de ${onNewPage.length} quadros (antes: ${before}px)`,
).toEqual([]);
expect(finalY, "rolagem final da página nova").toBe(0);
});
}
});
}