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(); } });