// Rendered-browser E2E: a real Chromium joins a match, the turn timer runs, the // player edits + saves a rune program, casts, sees filtered results, and replays // the match — verifying the recorded replay hashes match what was seen live. // // This is the browser layer of plan2.md Phase H ("Playwright end-to-end tests"). const { test, expect } = require("@playwright/test"); test("a player can join, cast, and replay a browser match", async ({ page }) => { await page.goto("/"); // Connects to the authoritative server. await expect(page.locator("#conn")).toHaveText("connected", { timeout: 10000 }); // The turn timer is running (header shows a turn + countdown). await expect(page.locator("#timer")).toContainText("turn", { timeout: 10000 }); // The arena rendered with the player's marker. await expect(page.locator(".cell.self")).toHaveCount(1, { timeout: 10000 }); // Domains panel shows the hidden-state redaction notice (visibility layer). await expect(page.locator("#redactions")).toContainText("withheld", { timeout: 10000 }); // Edit a rune program: add a couple of runes and save. await page.fill("#tok-a", "1"); await page.fill("#tok-b", "2"); await page.click("#btn-add"); await page.click("#btn-add"); await page.click("#btn-save"); // Observed diagnostics appear (names/counts only). await expect(page.locator("#diag-body")).toContainText("known reads", { timeout: 10000 }); // Cast and wait for a resolved-turn log line. await page.click("#btn-cast"); await expect(page.locator("#log")).toContainText("cast a rune program", { timeout: 15000 }); // Request and step the replay; the client verifies hashes vs. what it saw live. await page.click("#btn-replay"); await expect(page.locator("#replay-status")).toContainText("replay loaded", { timeout: 10000 }); await page.click("#btn-replay-step"); // A matching hash line is shown (no MISMATCH). await expect(page.locator(".hash-bad")).toHaveCount(0); });