110 lines
3.9 KiB
TypeScript
110 lines
3.9 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { type APIRequestContext, expect, type Page } from "@playwright/test";
|
|
|
|
/** Caminhos (`/`, `/cases/…`) de todas as rotas do /sitemap.xml, sem o domínio de produção. */
|
|
export async function sitemapPaths(request: APIRequestContext) {
|
|
const response = await request.get("/sitemap.xml");
|
|
if (response.status() !== 200)
|
|
throw new Error(`/sitemap.xml respondeu ${response.status()}`);
|
|
const xml = await response.text();
|
|
const paths = [...xml.matchAll(/<loc>\s*([^<\s]+)\s*<\/loc>/g)].map(
|
|
([, loc]) => {
|
|
const { pathname } = new URL(loc);
|
|
return pathname === "" ? "/" : pathname;
|
|
},
|
|
);
|
|
return [...new Set(paths)];
|
|
}
|
|
|
|
let devServer: Promise<boolean> | undefined;
|
|
|
|
/**
|
|
* O `BASE_URL` é um servidor de desenvolvimento (`next dev`)? O HTML dele traz o cliente de recarga a quente (HMR) e o
|
|
* React Refresh, que o build de produção não tem. Serve para a única coisa que só existe em um dos dois: avisos do
|
|
* React que só o desenvolvimento emite. (A barra de cookies é a mesma nos dois, e o gtag só carrega em produção.)
|
|
*/
|
|
export function isDevServer(request: APIRequestContext) {
|
|
devServer ??= request
|
|
.get("/")
|
|
.then((response) => response.text())
|
|
.then((html) => /hmr-client|react-refresh/.test(html))
|
|
.catch((error) => {
|
|
devServer = undefined;
|
|
throw error;
|
|
});
|
|
return devServer;
|
|
}
|
|
|
|
/** Nomes dos projetos de cliente, como a home os lista (public/portfolio-data.json, kind "cliente"). */
|
|
export function clientProjectNames() {
|
|
const data = JSON.parse(
|
|
readFileSync(
|
|
join(__dirname, "..", "public", "portfolio-data.json"),
|
|
"utf8",
|
|
),
|
|
) as { projects: Array<{ title: string; kind?: string }> };
|
|
return data.projects
|
|
.filter((project) => project.kind === "cliente")
|
|
.map((project) => project.title);
|
|
}
|
|
|
|
/** Texto do cabeçalho da seção de contato da home. */
|
|
export const CONTACT_HEADING =
|
|
"Vamos conversar sobre o que sua empresa precisa.";
|
|
|
|
export const DESKTOP = { width: 1440, height: 900 } as const;
|
|
export const PHONE = { width: 390, height: 844 } as const;
|
|
|
|
/** Opções de `test.use` do computador. */
|
|
export const DESKTOP_USE = { viewport: DESKTOP } as const;
|
|
|
|
/**
|
|
* Opções de `test.use` de um celular de verdade: a janela de 390x844 mais `isMobile` (viewport de celular, `<meta
|
|
* viewport>` valendo) e `hasTouch` (toque, `tap()`), e não só uma janela estreita.
|
|
*/
|
|
export const PHONE_USE = {
|
|
viewport: PHONE,
|
|
isMobile: true,
|
|
hasTouch: true,
|
|
deviceScaleFactor: 2,
|
|
} as const;
|
|
|
|
/** Chave do consentimento no localStorage (`CONSENT_STORAGE_KEY` em lib/analytics.ts). */
|
|
export const CONSENT_STORAGE_KEY = "evandro.analytics-consent.v1";
|
|
|
|
/** Os controles da barra de cookies, na ordem do Tab. */
|
|
export const COOKIE_BAR_CONTROLS = [
|
|
"Política de privacidade",
|
|
"Aceitar",
|
|
"Recusar",
|
|
] as const;
|
|
|
|
/**
|
|
* Deixa o consentimento já salvo no navegador (como quem aceitou ou recusou numa visita anterior): chamar antes do
|
|
* `page.goto`. Com ele a barra de cookies não abre. "denied" por padrão, para o gtag não carregar em produção.
|
|
*/
|
|
export async function saveConsent(
|
|
page: Page,
|
|
value: "granted" | "denied" = "denied",
|
|
) {
|
|
await page.addInitScript(
|
|
([key, stored]) => window.localStorage.setItem(key, stored),
|
|
[CONSENT_STORAGE_KEY, value],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* A barra de cookies da primeira visita (id `cookie-bar`, `COOKIE_BAR_ID` em lib/analytics.ts), fixa na base da tela,
|
|
* antes do cabeçalho no documento. Ela é a mesma em qualquer servidor, de desenvolvimento ou de produção (só o
|
|
* carregamento do gtag depende do ambiente): se não aparecer, o teste reprova. Devolve o localizador da barra.
|
|
*/
|
|
export async function cookieBar(page: Page) {
|
|
const bar = page.getByRole("dialog", { name: "Cookies e privacidade" });
|
|
await expect(
|
|
bar,
|
|
"a barra de cookies não apareceu na primeira visita",
|
|
).toBeVisible({ timeout: 10_000 });
|
|
return bar;
|
|
}
|