import { type Browser, chromium, expect, type Page, test, } from "@playwright/test"; import type { ResultadoDaBancada } from "../app/jogo/Bancada"; import { DESKTOP } from "./helpers"; /** Abre a bancada, espera `window.__bancada` aparecer e o devolve. */ async function medir(page: Page, busca: string, espera: number) { const resposta = await page.goto(`/jogo/bancada?${busca}`); expect(resposta?.status()).toBe(200); await page.waitForFunction(() => window.__bancada !== undefined, null, { timeout: espera, }); const resultado = (await page.evaluate( () => window.__bancada, )) as ResultadoDaBancada; console.log(`bancada ${busca}: ${JSON.stringify(resultado)}`); return resultado; } test("a bancada abre sem indexação, mede e publica o resultado sem erro no console", async ({ page, }) => { const erros: string[] = []; page.on("console", (mensagem) => { if (mensagem.type() === "error") erros.push(mensagem.text()); }); page.on("pageerror", (erro) => erros.push(erro.message)); const resultado = await medir(page, "zumbis=4&seg=2", 60_000); await expect(page.locator('meta[name="robots"]')).toHaveAttribute( "content", "noindex, nofollow", ); if ("erro" in resultado) expect(resultado.erro).toBe("sem-webgl"); else { expect(resultado.zumbis).toBe(4); expect(resultado.quadros).toBeGreaterThan(0); expect(resultado.p95).toBeGreaterThan(0); expect(typeof resultado.trabalhoP95).toBe("number"); } expect(erros).toEqual([]); }); test.describe("com GPU (BANCADA_GPU=1)", () => { test.skip(!process.env.BANCADA_GPU, "precisa de GPU: BANCADA_GPU=1"); // O Playwright recusa `test.use({ launchOptions })` dentro de um describe (exigiria outro worker): o navegador com // os argumentos de GPU abre aqui, só para este bloco, com o mesmo `PW_CHROMIUM` da configuração. let navegador: Browser; test.beforeAll(async () => { navegador = await chromium.launch({ executablePath: process.env.PW_CHROMIUM || undefined, args: [ "--enable-gpu", "--ignore-gpu-blocklist", "--use-angle=vulkan", "--enable-features=Vulkan", ], }); }); test.afterAll(() => navegador?.close()); test("16 zumbis em 1440×900: p95 até 16,7 ms", async ({ baseURL }) => { const contexto = await navegador.newContext({ viewport: DESKTOP, baseURL }); const resultado = await medir( await contexto.newPage(), "zumbis=16&seg=20", 90_000, ); if ("erro" in resultado) throw new Error("sem WebGL com GPU"); expect(resultado.p95).toBeLessThanOrEqual(16.7); }); test("16 zumbis com a CPU 4× mais lenta: p95 até 33 ms", async ({ baseURL, }) => { const contexto = await navegador.newContext({ viewport: DESKTOP, baseURL }); const page = await contexto.newPage(); const cdp = await contexto.newCDPSession(page); await cdp.send("Emulation.setCPUThrottlingRate", { rate: 4 }); const resultado = await medir(page, "zumbis=16&seg=20", 110_000); if ("erro" in resultado) throw new Error("sem WebGL com GPU"); expect(resultado.p95).toBeLessThanOrEqual(33); }); test("memória (CA9): 3ª medição com as mesmas geometrias e texturas da 1ª", async ({ baseURL, }) => { const contexto = await navegador.newContext({ viewport: DESKTOP, baseURL }); const page = await contexto.newPage(); const primeira = await medir(page, "zumbis=16&seg=3", 90_000); if ("erro" in primeira) throw new Error("sem WebGL com GPU"); let ultima: ResultadoDaBancada = primeira; for (let i = 0; i < 2; i += 1) { const botao = page.getByRole("button", { name: "Medir de novo" }); await botao.click(); await botao.waitFor({ state: "detached", timeout: 30_000 }); await page.waitForFunction(() => window.__bancada !== undefined, null, { timeout: 90_000, }); ultima = (await page.evaluate( () => window.__bancada, )) as ResultadoDaBancada; console.log(`bancada medição ${i + 2}: ${JSON.stringify(ultima)}`); } if ("erro" in ultima) throw new Error("sem WebGL com GPU"); expect(ultima.geometrias).toBe(primeira.geometrias); expect(ultima.texturas).toBe(primeira.texturas); }); });