// Vitest unit coverage for the pure `applyOrderOverlay` projection. // Phase 14 understands `planetRename` only; future phases (set // production, route updates) will extend the overlay and need // equivalent cases here. import { describe, expect, test } from "vitest"; import { applyOrderOverlay, type GameReport, type ReportPlanet, } from "../src/api/game-state"; import type { CommandStatus, OrderCommand } from "../src/sync/order-types"; function makePlanet(overrides: Partial): ReportPlanet { return { number: 0, name: "", x: 0, y: 0, kind: "local", owner: null, size: null, resources: null, industryStockpile: null, materialsStockpile: null, industry: null, population: null, colonists: null, production: null, freeIndustry: null, ...overrides, }; } function makeReport(planets: ReportPlanet[]): GameReport { return { turn: 4, mapWidth: 4000, mapHeight: 4000, planetCount: planets.length, planets, }; } describe("applyOrderOverlay", () => { test("returns the same report when no commands match", () => { const report = makeReport([makePlanet({ number: 1, name: "Earth" })]); const out = applyOrderOverlay(report, [], {}); expect(out).toBe(report); }); test("renames a planet on applied commands", () => { const report = makeReport([ makePlanet({ number: 1, name: "Earth" }), makePlanet({ number: 2, name: "Mars" }), ]); const cmd: OrderCommand = { kind: "planetRename", id: "cmd-1", planetNumber: 1, name: "New Earth", }; const statuses: Record = { "cmd-1": "applied" }; const out = applyOrderOverlay(report, [cmd], statuses); expect(out).not.toBe(report); expect(out.planets[0]!.name).toBe("New Earth"); expect(out.planets[1]!.name).toBe("Mars"); // raw report stays untouched expect(report.planets[0]!.name).toBe("Earth"); }); test("renames on submitting too (in-flight optimistic)", () => { const report = makeReport([makePlanet({ number: 1, name: "Earth" })]); const cmd: OrderCommand = { kind: "planetRename", id: "cmd-1", planetNumber: 1, name: "Pending", }; const out = applyOrderOverlay(report, [cmd], { "cmd-1": "submitting" }); expect(out.planets[0]!.name).toBe("Pending"); }); test("skips unsubmitted statuses (draft/valid/invalid/rejected)", () => { const report = makeReport([makePlanet({ number: 1, name: "Earth" })]); const cmd: OrderCommand = { kind: "planetRename", id: "cmd-1", planetNumber: 1, name: "Tentative", }; for (const status of ["draft", "valid", "invalid", "rejected"] as const) { const out = applyOrderOverlay(report, [cmd], { "cmd-1": status }); expect(out.planets[0]!.name).toBe("Earth"); } }); test("ignores rename for missing planet (visibility lost)", () => { const report = makeReport([makePlanet({ number: 1, name: "Earth" })]); const cmd: OrderCommand = { kind: "planetRename", id: "cmd-1", planetNumber: 99, name: "Phantom", }; const out = applyOrderOverlay(report, [cmd], { "cmd-1": "applied" }); expect(out).toBe(report); }); test("placeholder commands pass through", () => { const report = makeReport([makePlanet({ number: 1, name: "Earth" })]); const cmd: OrderCommand = { kind: "placeholder", id: "cmd-1", label: "noop", }; const out = applyOrderOverlay(report, [cmd], { "cmd-1": "applied" }); expect(out).toBe(report); }); test("multiple renames apply in command order", () => { const report = makeReport([makePlanet({ number: 1, name: "Old" })]); const first: OrderCommand = { kind: "planetRename", id: "cmd-1", planetNumber: 1, name: "Mid", }; const second: OrderCommand = { kind: "planetRename", id: "cmd-2", planetNumber: 1, name: "Final", }; const out = applyOrderOverlay(report, [first, second], { "cmd-1": "applied", "cmd-2": "applied", }); expect(out.planets[0]!.name).toBe("Final"); }); });