import { expect, test } from "@playwright/test"; test("loads standalone and keeps the core play workflow local", async ({ page, }) => { const runtimeErrors: string[] = []; page.on("pageerror", (error) => runtimeErrors.push(error.message)); page.on("console", (message) => { if (message.type() === "error") runtimeErrors.push(message.text()); }); await page.goto("/deep/nested/sudoku/"); await expect( page.getByRole("heading", { name: "A first classic" }), ).toBeVisible(); const grid = page.getByRole("grid", { name: "9 by 9 Sudoku grid" }); await expect(grid).toBeVisible(); await expect(grid.getByRole("gridcell")).toHaveCount(81); await grid.getByRole("gridcell", { name: "Row 1, column 3, empty" }).click(); await page .getByRole("group", { name: "Digits" }) .getByRole("button", { name: "2", exact: true }) .click(); await expect( grid.getByRole("gridcell", { name: "Row 1, column 3, 2" }), ).toBeVisible(); await page.getByRole("button", { name: "Undo" }).click(); await expect( grid.getByRole("gridcell", { name: "Row 1, column 3, empty" }), ).toBeVisible(); const placedFour = grid.getByRole("gridcell", { name: "Row 1, column 1, 4", }); await placedFour.click({ modifiers: ["Control"] }); expect(await grid.locator(".is-digit-highlighted").count()).toBeGreaterThan( 1, ); await placedFour.click({ modifiers: ["Control"] }); await expect(grid.locator(".is-digit-highlighted")).toHaveCount(0); await page.getByRole("button", { name: "Helpers" }).click(); await expect( page.getByRole("heading", { name: "Sudoku helpers" }), ).toBeVisible(); await expect( page.getByRole("tab", { name: "Killer combinations" }), ).toHaveAttribute("aria-selected", "true"); await expect(page.locator(".helper-result")).toContainText("4 combinations"); await page.getByRole("button", { name: "Import / export" }).click(); await expect( page.getByRole("heading", { name: "Import and export" }), ).toBeVisible(); await expect( page.getByText(/Server-only short IDs are never fetched\./u), ).toBeVisible(); await expect( page.getByText(/Share links are self-contained\./u), ).toBeVisible(); expect(runtimeErrors).toEqual([]); }); test("replaces setter cages and generates a rated variant", async ({ page, }) => { const runtimeErrors: string[] = []; page.on("pageerror", (error) => runtimeErrors.push(error.message)); page.on("console", (message) => { if (message.type() === "error") runtimeErrors.push(message.text()); }); await page.goto("/deep/nested/sudoku/"); await page.getByRole("button", { name: "New blank" }).click(); const grid = page.getByRole("grid", { name: "9 by 9 Sudoku grid" }); await grid.getByRole("gridcell", { name: "Row 1, column 1, empty" }).click(); await grid .getByRole("gridcell", { name: "Row 1, column 2, empty" }) .click({ modifiers: ["Shift"] }); await page.getByRole("spinbutton", { name: "Cage sum" }).fill("3"); await page.getByRole("button", { name: "Add / replace cage" }).click(); await expect(page.getByText("3 cage · 2 cells")).toBeVisible(); await page.getByRole("spinbutton", { name: "Cage sum" }).fill("4"); await page.getByRole("button", { name: "Add / replace cage" }).click(); await expect(page.getByText("3 cage · 2 cells")).toHaveCount(0); await expect(page.getByText("4 cage · 2 cells")).toBeVisible(); await page.getByRole("button", { name: "Remove selected cage" }).click(); await expect(page.getByText("4 cage · 2 cells")).toHaveCount(0); await page.getByRole("button", { name: "Generate", exact: true }).click(); await page.getByLabel("Variant").selectOption("thermo"); await page .getByRole("combobox", { name: "Grid", exact: true }) .selectOption("4"); await page.getByLabel("Requested profile").selectOption("beginner"); await page.getByLabel("Seed").fill("browser-thermo"); await page.getByRole("button", { name: "Generate Thermo" }).click(); await expect( page.getByRole("heading", { name: "Thermo · browser-thermo" }), ).toBeVisible({ timeout: 60_000 }); await expect(page.getByText("Difficulty assessment")).toBeVisible(); await expect(page.locator(".difficulty-card .status-pill")).toHaveText( "unique", ); await expect(page.locator(".constraint-thermo")).not.toHaveCount(0); expect(runtimeErrors).toEqual([]); }); test("uses distinct numbered sum badges and directional inequalities", async ({ page, }) => { await page.goto("/deep/nested/sudoku/"); const examples = page.getByLabel("Open built-in puzzle"); await examples.selectOption("xv"); await expect( page.getByRole("heading", { name: "Five or ten" }), ).toBeVisible(); await expect(page.locator(".constraint-xv--5 text").first()).toHaveText("5"); await expect(page.locator(".constraint-xv--10 text").first()).toHaveText( "10", ); await examples.selectOption("inequality"); await expect( page.getByRole("heading", { name: "Lesser and greater" }), ).toBeVisible(); await expect(page.locator(".constraint-inequality")).not.toHaveCount(0); await expect( page.locator(".constraint-inequality-tip").first(), ).toBeVisible(); });