feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
CI / audit (push) Successful in 10m48s
CI / verify (push) Successful in 19m2s
CI / deploy (push) Successful in 2m14s
CI / e2e (push) Failing after 36m15s

Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
This commit is contained in:
evandro committed 2026-11-10 19:37:10 -03:00
1 parent c7d09d63d4
commit 67b32fcab3
118 files changed
+16730

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
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);
});
});