// Phase 19 end-to-end smoke against the synthetic-report path. Loads // a hand-crafted JSON with a Tancordia-style mix of planets and ship // groups through the DEV-only file picker on `/lobby`, lets the // in-game shell layout swap into synthetic mode, and asserts the map // canvas mounts. Detailed click / hit-test fidelity for ship-group // variants lives in the unit tests (`tests/state-binding-groups.test.ts` // and `tests/inspector-ship-group.test.ts`); this spec catches the // glue: lobby loader → in-memory registry → layout bypass → renderer // boot. import { expect, test } from "@playwright/test"; const SYNTHETIC_REPORT_FIXTURE = { turn: 39, mapWidth: 200, mapHeight: 200, mapPlanets: 4, race: "Earthlings", player: [ { name: "Earthlings", drive: 5, weapons: 3, shields: 2, cargo: 1, population: 1000, industry: 1000, planets: 2, relation: "-", votes: 5, extinct: false, }, ], localPlanet: [ { number: 1, name: "Earth", x: 50, y: 100, size: 1000, population: 1000, industry: 1000, resources: 10, production: "Capital", capital: 0, material: 0, colonists: 100, freeIndustry: 1000, }, { number: 2, name: "Mars", x: 150, y: 100, size: 500, population: 500, industry: 500, resources: 5, production: "Capital", capital: 0, material: 0, colonists: 50, freeIndustry: 500, }, ], otherPlanet: [], uninhabitedPlanet: [], unidentifiedPlanet: [ { number: 3, x: 50, y: 50 }, { number: 4, x: 150, y: 50 }, ], localShipClass: [ { name: "Frontier", drive: 5, armament: 0, weapons: 0, shields: 0, cargo: 1, mass: 12, }, ], localGroup: [ { id: "11111111-2222-3333-4444-555555555555", number: 2, class: "Frontier", tech: { drive: 5, weapons: 0, shields: 0, cargo: 1 }, cargo: "-", load: 0, destination: 1, speed: 0, mass: 12, state: "In_Orbit", }, ], otherGroup: [], incomingGroup: [ { origin: 4, destination: 1, distance: 50, speed: 25, mass: 4, }, ], unidentifiedGroup: [], localFleet: [], }; test("synthetic-report loader navigates from lobby to map and renders", async ({ page, }) => { await page.goto("/lobby"); await expect(page.getByTestId("lobby-synthetic-section")).toBeVisible(); const file = page.getByTestId("lobby-synthetic-file"); await file.setInputFiles({ name: "phase19.json", mimeType: "application/json", buffer: Buffer.from(JSON.stringify(SYNTHETIC_REPORT_FIXTURE)), }); await page.waitForURL(/\/games\/synthetic-[^/]+\/map$/, { timeout: 5_000, }); // The renderer canvas mounts inside the active-view host. Even if // the WebGL/WebGPU backend is unavailable in CI, the layout still // reaches `ready` once the report is loaded — the assertion is // gentle on purpose so the spec doesn't flake on headless renders. const canvas = page.locator("canvas"); await expect(canvas.first()).toBeVisible({ timeout: 10_000 }); });