2b1ad2161a
play_canvas.spec.js covers the window.__FERROUS_DEBUG__ bridge on the /play route (five tests): bridge availability + seed param, draw3 URL param, applyLegalMove/undo round-trip, failureReport schema, and autonomous autoplay invariant batch across 7 seeds. All tests drive exclusively through the debug bridge — no DOM selectors, because the Bevy canvas is a single <canvas> element with no HTML controls. Also update SESSION_HANDOFF.md to reflect post-v0.35.1 work (10 commits since 2026-05-18 handoff), new e2e architecture notes, and HiDPI fix doc. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
2.8 KiB
JavaScript
82 lines
2.8 KiB
JavaScript
const { test, expect } = require("@playwright/test");
|
|
|
|
async function gotoReadyPlay(page, seed = 42, draw3 = false) {
|
|
const suffix = draw3 ? "&draw3=" : "";
|
|
await page.goto(`/play?seed=${seed}${suffix}`);
|
|
await page.waitForFunction(
|
|
() =>
|
|
typeof window.__FERROUS_DEBUG__ === "object" &&
|
|
window.__FERROUS_DEBUG__.seed() !== null,
|
|
null,
|
|
{ timeout: 30_000 }
|
|
);
|
|
}
|
|
|
|
test("play loads and exposes debug bridge", async ({ page }) => {
|
|
await gotoReadyPlay(page, 42);
|
|
|
|
const seed = await page.evaluate(() => window.__FERROUS_DEBUG__.seed());
|
|
expect(seed).toBe(42);
|
|
|
|
const legalMoves = await page.evaluate(() => window.__FERROUS_DEBUG__.legalMoves());
|
|
expect(Array.isArray(legalMoves)).toBeTruthy();
|
|
expect(legalMoves.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
test("play respects draw3 URL param", async ({ page }) => {
|
|
await gotoReadyPlay(page, 77, true);
|
|
|
|
const snap = await page.evaluate(() => window.__FERROUS_DEBUG__.snapshot());
|
|
expect(snap).not.toBeNull();
|
|
expect(snap.draw_mode).toBe("DrawThree");
|
|
});
|
|
|
|
test("play debug bridge apply and undo work", async ({ page }) => {
|
|
await gotoReadyPlay(page, 42);
|
|
|
|
const baseline = await page.evaluate(() => window.__FERROUS_DEBUG__.moveHistory().length);
|
|
|
|
const applied = await page.evaluate(() => window.__FERROUS_DEBUG__.applyLegalMove(0));
|
|
expect(applied?.ok).toBeTruthy();
|
|
|
|
await expect
|
|
.poll(() => page.evaluate(() => window.__FERROUS_DEBUG__.moveHistory().length))
|
|
.toBe(baseline + 1);
|
|
|
|
const undone = await page.evaluate(() => window.__FERROUS_DEBUG__.undo());
|
|
expect(undone?.ok).toBeTruthy();
|
|
|
|
await expect
|
|
.poll(() => page.evaluate(() => window.__FERROUS_DEBUG__.moveHistory().length))
|
|
.toBe(baseline);
|
|
});
|
|
|
|
test("play failure report contains replay diagnostics", async ({ page }) => {
|
|
await gotoReadyPlay(page, 42);
|
|
|
|
const report = await page.evaluate(() => window.__FERROUS_DEBUG__.failureReport());
|
|
expect(report).not.toBeNull();
|
|
expect(typeof report.seed).toBe("number");
|
|
expect(Array.isArray(report.moveHistory)).toBeTruthy();
|
|
expect(Array.isArray(report.legalMoves)).toBeTruthy();
|
|
expect(report.currentState).toBeTruthy();
|
|
expect(report.invariants).toBeTruthy();
|
|
});
|
|
|
|
test("play autonomous autoplay keeps invariants stable across seed batch", async ({ page }) => {
|
|
test.setTimeout(120_000);
|
|
const seeds = [0, 1, 2, 5, 13, 42, 77];
|
|
|
|
for (const seed of seeds) {
|
|
await gotoReadyPlay(page, seed);
|
|
const run = await page.evaluate(() =>
|
|
window.__FERROUS_DEBUG__.runAutoplay({
|
|
maxSteps: 220,
|
|
maxVisitsPerState: 2,
|
|
policy: "loop_aware",
|
|
})
|
|
);
|
|
expect(run.ok, `seed ${seed} failed: ${JSON.stringify(run)}`).toBeTruthy();
|
|
}
|
|
});
|