feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
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:
1 parent
c7d09d63d4
commit
67b32fcab3
118 files changed
+16730
No files matched your search
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user