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; // 5 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, ); });