test: e2e mais rígida e .gitattributes
Zero telas sem texto no computador e no celular; atalho de teclado em até 4 Tabs e linear em até 36 com o inventário das paradas; ciclo de foco do menu com a barra de cookies; oferta e cabeçalho levando ao formulário; foco vindo de outra página; separador da faixa de clientes; contagem de pôsteres da SEV. .gitattributes com eol=lf.
This commit is contained in:
1 parent
204ebd5fa5
commit
2cd4a98c55
10 files changed
+588
-87
No files matched your search
@@ -0,0 +1,80 @@
|
||||
import { expect, type Page, test } from "@playwright/test";
|
||||
import { DESKTOP, PHONE } from "./helpers";
|
||||
|
||||
/**
|
||||
* (j) O pôster da SEV Moda Íntima não se repete: em /servicos e em /cases ele aparece no máximo 2 vezes (meta da
|
||||
* rodada 4), contando todo elemento que o mostra ao navegador (<img>, <video poster>, fundo CSS) e que não esteja
|
||||
* dentro da própria página do case. Conta o que está no HTML, visível ou não, porque o que está no HTML é o que o
|
||||
* navegador baixa. O mesmo vale nas duas larguras.
|
||||
*/
|
||||
|
||||
const SEV_ASSETS = "/videos/sev-modaintima/";
|
||||
const MAX_SEV_POSTERS = 2;
|
||||
const PAGES = ["/servicos", "/cases"] as const;
|
||||
const VIEWPORTS = [
|
||||
{ name: "computador 1440x900", size: DESKTOP },
|
||||
{ name: "celular 390x844", size: PHONE },
|
||||
] as const;
|
||||
|
||||
/** Elementos que mostram um arquivo de /videos/sev-modaintima/, descritos em texto. */
|
||||
function sevPosters(page: Page) {
|
||||
return page.evaluate((assets) => {
|
||||
const decoded = (value: string | null) => {
|
||||
try {
|
||||
return decodeURIComponent(value ?? "");
|
||||
} catch {
|
||||
return value ?? "";
|
||||
}
|
||||
};
|
||||
const found: string[] = [];
|
||||
for (const element of document.querySelectorAll("*")) {
|
||||
const sources = [
|
||||
element.getAttribute("src"),
|
||||
element.getAttribute("srcset"),
|
||||
element.getAttribute("poster"),
|
||||
element instanceof HTMLElement ? element.style.backgroundImage : null,
|
||||
];
|
||||
if (element instanceof HTMLElement && element.tagName !== "HTML")
|
||||
sources.push(getComputedStyle(element).backgroundImage);
|
||||
const hit = sources.find((value) => decoded(value).includes(assets));
|
||||
if (hit)
|
||||
found.push(
|
||||
`<${element.tagName.toLowerCase()}> ${decoded(hit).slice(0, 110)}`,
|
||||
);
|
||||
}
|
||||
return found;
|
||||
}, SEV_ASSETS);
|
||||
}
|
||||
|
||||
for (const { name, size } of VIEWPORTS) {
|
||||
test.describe(`pôster da SEV, ${name}`, () => {
|
||||
test.use({ viewport: size });
|
||||
|
||||
// o detector enxerga o pôster onde ele certamente está (o hero da home e o próprio case): sem isso, "0 imagens"
|
||||
// poderia ser só um seletor que não acha nada
|
||||
for (const path of ["/", "/cases/sev-modaintima"]) {
|
||||
test(`${path}: o detector acha o pôster da SEV`, async ({ page }) => {
|
||||
await page.goto(path, { waitUntil: "load" });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
expect((await sevPosters(page)).length).toBeGreaterThan(0);
|
||||
});
|
||||
}
|
||||
|
||||
for (const path of PAGES) {
|
||||
test(`${path}: no máximo ${MAX_SEV_POSTERS} imagens da SEV fora do próprio case`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(path, { waitUntil: "load" });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const posters = await sevPosters(page);
|
||||
|
||||
expect(
|
||||
posters.length,
|
||||
`${path}: ${posters.length} elemento(s) mostram arquivos da SEV (meta: no máximo ${MAX_SEV_POSTERS}):\n${posters.join("\n")}`,
|
||||
).toBeLessThanOrEqual(MAX_SEV_POSTERS);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user