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.
124 lines
4.7 KiB
TypeScript
124 lines
4.7 KiB
TypeScript
import { expect, type Page, test } from "@playwright/test";
|
|
import { clientProjectNames } from "./helpers";
|
|
|
|
/**
|
|
* (i) Faixa "Já entregue para" do hero (ClientStrip), em larguras de celular a computador: o ponto separador (·) só
|
|
* aparece ENTRE itens da mesma linha. O ponto abre cada item (menos o primeiro) e a margem negativa o esconde, pelo
|
|
* `overflow-x: clip` da lista, quando o item abre uma linha nova. Então, para cada item depois do primeiro:
|
|
* ponto visível <=> o item está na mesma linha do anterior.
|
|
* Nenhuma linha começa nem termina com "·". O Jest só confere as classes; só o navegador mostra o corte.
|
|
* "Visível" = o centro do ponto está dentro da caixa da lista (o que o corte deixa passar).
|
|
*/
|
|
|
|
const WIDTHS = [320, 360, 390, 430, 560, 768, 1024, 1440];
|
|
|
|
async function stripItems(page: Page) {
|
|
return page.evaluate(() => {
|
|
const label = Array.from(document.querySelectorAll("p")).find(
|
|
(paragraph) => paragraph.textContent?.trim() === "Já entregue para:",
|
|
);
|
|
const list = label?.parentElement?.querySelector("ul");
|
|
if (!list) return null;
|
|
const listBox = list.getBoundingClientRect();
|
|
const items = Array.from(list.querySelectorAll("li")).map((item) => {
|
|
const dot = item.querySelector("[aria-hidden='true']");
|
|
const dotBox = dot?.getBoundingClientRect();
|
|
return {
|
|
text: (item.textContent ?? "").replace(/\s+/g, " ").trim(),
|
|
// o centro vertical: um item mais baixo (os anos) fica centrado na linha e tem outro topo
|
|
center: Math.round(
|
|
item.getBoundingClientRect().top +
|
|
item.getBoundingClientRect().height / 2,
|
|
),
|
|
hasDot: Boolean(dot),
|
|
dotCenter: dotBox ? dotBox.left + dotBox.width / 2 : null,
|
|
};
|
|
});
|
|
return {
|
|
items,
|
|
listLeft: listBox.left,
|
|
listRight: listBox.right,
|
|
overflowX: getComputedStyle(list).overflowX,
|
|
};
|
|
});
|
|
}
|
|
|
|
/** Confere a regra "ponto visível <=> mesma linha do anterior" na faixa como ela está agora. Devolve quantas quebras há. */
|
|
async function expectDotsOnlyBetweenItemsOfOneLine(page: Page, where: string) {
|
|
const strip = await stripItems(page);
|
|
expect(strip, `${where}: a faixa 'Já entregue para:' no hero`).not.toBeNull();
|
|
if (!strip) return 0;
|
|
const { items, listLeft, listRight, overflowX } = strip;
|
|
// 4 clientes + os anos de experiência
|
|
expect(items.length, `${where}: itens da faixa`).toBeGreaterThanOrEqual(
|
|
clientProjectNames().length,
|
|
);
|
|
expect(overflowX, `${where}: o corte do ponto depende de overflow-x`).toBe(
|
|
"clip",
|
|
);
|
|
expect(items[0].hasDot, `${where}: o primeiro item não tem ponto`).toBe(
|
|
false,
|
|
);
|
|
|
|
const report = items
|
|
.map(
|
|
(item) =>
|
|
`${item.center}px ${item.hasDot ? `ponto em ${Math.round(item.dotCenter ?? 0)}` : "sem ponto"} "${item.text}"`,
|
|
)
|
|
.join("\n");
|
|
let wraps = 0;
|
|
for (let index = 1; index < items.length; index++) {
|
|
const item = items[index];
|
|
const sameLine = Math.abs(item.center - items[index - 1].center) < 12;
|
|
if (!sameLine) wraps += 1;
|
|
const visible =
|
|
item.dotCenter !== null &&
|
|
item.dotCenter >= listLeft &&
|
|
item.dotCenter <= listRight;
|
|
expect(
|
|
visible,
|
|
`${where}, "${item.text}": ${sameLine ? "na mesma linha do anterior, o ponto precisa aparecer" : "abre uma linha nova, o ponto precisa ficar escondido"} (lista de ${Math.round(listLeft)} a ${Math.round(listRight)}px)\n${report}`,
|
|
).toBe(sameLine);
|
|
}
|
|
return wraps;
|
|
}
|
|
|
|
for (const width of WIDTHS) {
|
|
test(`faixa de clientes a ${width}px: o ponto só aparece entre itens da mesma linha`, async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize({ width, height: 900 });
|
|
await page.goto("/", { waitUntil: "load" });
|
|
await page.waitForTimeout(800);
|
|
|
|
await expectDotsOnlyBetweenItemsOfOneLine(page, `${width}px`);
|
|
});
|
|
}
|
|
|
|
test("faixa de clientes em colunas estreitas (quebra forçada): nenhuma linha começa nem termina com o ponto", async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize({ width: 1440, height: 900 });
|
|
await page.goto("/", { waitUntil: "load" });
|
|
await page.waitForTimeout(800);
|
|
|
|
let wrappedAtLeastOnce = false;
|
|
for (const columnWidth of [140, 200, 260, 320, 380, 440, 520, 600]) {
|
|
await page.evaluate((px) => {
|
|
const label = Array.from(document.querySelectorAll("p")).find(
|
|
(paragraph) => paragraph.textContent?.trim() === "Já entregue para:",
|
|
);
|
|
const wrapper = label?.parentElement;
|
|
if (wrapper) wrapper.style.maxWidth = `${px}px`;
|
|
}, columnWidth);
|
|
const wraps = await expectDotsOnlyBetweenItemsOfOneLine(
|
|
page,
|
|
`coluna de ${columnWidth}px`,
|
|
);
|
|
if (wraps > 0) wrappedAtLeastOnce = true;
|
|
}
|
|
expect(wrappedAtLeastOnce, "alguma largura quebrou a faixa em linhas").toBe(
|
|
true,
|
|
);
|
|
});
|