// Vitest component coverage for the Phase 19 read-only ship-group // inspector. The inspector dispatches on the selection variant — // local / other / incoming / unidentified — and renders a fixed set // of fields per branch. The tests assert each branch surfaces the // fields the acceptance criteria call out, plus the // "no destination resolution" fallback. import "@testing-library/jest-dom/vitest"; import { render } from "@testing-library/svelte"; import { beforeEach, describe, expect, test } from "vitest"; import { i18n } from "../src/lib/i18n/index.svelte"; import type { ReportIncomingShipGroup, ReportLocalShipGroup, ReportOtherShipGroup, ReportPlanet, ReportUnidentifiedShipGroup, } from "../src/api/game-state"; import ShipGroup, { type ShipGroupSelection, } from "../src/lib/inspectors/ship-group.svelte"; const PLANETS: ReportPlanet[] = [ { number: 17, name: "Castle", x: 100, y: 100, kind: "local", owner: null, size: 1000, resources: 10, industryStockpile: 0, materialsStockpile: 0, industry: 1000, population: 1000, colonists: 0, production: "Capital", freeIndustry: 1000, }, { number: 99, name: "Outpost", x: 200, y: 200, kind: "other", owner: "Foreign", size: 500, resources: 5, industryStockpile: 0, materialsStockpile: 0, industry: 500, population: 500, colonists: 0, production: "Capital", freeIndustry: 500, }, ]; beforeEach(() => { i18n.resetForTests("en"); }); function localGroup( overrides: Partial = {}, ): ReportLocalShipGroup { return { id: "uuid-1", count: 2, class: "Frontier", tech: { drive: 5, weapons: 0, shields: 0, cargo: 1 }, cargo: "NONE", load: 0, destination: 17, origin: null, range: null, speed: 0, mass: 12, state: "In_Orbit", fleet: null, ...overrides, }; } describe("ship-group inspector", () => { test("renders the on-planet local group with all required fields", () => { const selection: ShipGroupSelection = { variant: "local", group: localGroup(), }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect(ui.getByTestId("inspector-ship-group-class")).toHaveTextContent( "Frontier", ); expect(ui.getByTestId("inspector-ship-group-field-count")).toHaveTextContent( "2", ); expect(ui.getByTestId("inspector-ship-group-field-drive")).toHaveTextContent( "5", ); expect( ui.getByTestId("inspector-ship-group-field-location"), ).toHaveTextContent("Castle"); expect(ui.getByTestId("inspector-ship-group-field-state")).toHaveTextContent( "In_Orbit", ); expect( ui.queryByTestId("inspector-ship-group-field-distance"), ).toBeNull(); }); test("renders the in-hyperspace local group with from / to / distance", () => { const selection: ShipGroupSelection = { variant: "local", group: localGroup({ origin: 17, range: 4.5, destination: 99, state: "In_Space", }), }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect(ui.getByTestId("inspector-ship-group-field-from")).toHaveTextContent( "Castle", ); expect(ui.getByTestId("inspector-ship-group-field-to")).toHaveTextContent( "Outpost", ); expect( ui.getByTestId("inspector-ship-group-field-distance"), ).toHaveTextContent("4.5"); expect( ui.queryByTestId("inspector-ship-group-field-location"), ).toBeNull(); }); test("renders cargo type and amount when the group is loaded", () => { const selection: ShipGroupSelection = { variant: "local", group: localGroup({ cargo: "COL", load: 1.05 }), }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); const cargo = ui.getByTestId("inspector-ship-group-field-cargo-load"); expect(cargo).toHaveTextContent("colonists"); expect(cargo).toHaveTextContent("1.05"); }); test("renders foreign group without fleet/state but with full tech", () => { const group: ReportOtherShipGroup = { count: 5, class: "Cruiser", tech: { drive: 8, weapons: 4, shields: 3, cargo: 1 }, cargo: "NONE", load: 0, destination: 99, origin: null, range: null, speed: 0, mass: 50, }; const selection: ShipGroupSelection = { variant: "other", group }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect(ui.getByTestId("inspector-ship-group-class")).toHaveTextContent( "Cruiser", ); expect(ui.queryByTestId("inspector-ship-group-field-fleet")).toBeNull(); expect(ui.queryByTestId("inspector-ship-group-field-state")).toBeNull(); }); test("incoming group surfaces ETA and trajectory fields", () => { const group: ReportIncomingShipGroup = { origin: 99, destination: 17, distance: 80, speed: 25, mass: 4, }; const selection: ShipGroupSelection = { variant: "incoming", group }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect(ui.getByTestId("inspector-ship-group-field-from")).toHaveTextContent( "Outpost", ); expect(ui.getByTestId("inspector-ship-group-field-to")).toHaveTextContent( "Castle", ); // ETA = ceil(80 / 25) = 4. expect(ui.getByTestId("inspector-ship-group-field-eta")).toHaveTextContent( "4", ); expect( ui.getByTestId("inspector-ship-group-field-distance"), ).toHaveTextContent("80"); }); test("incoming group with zero speed renders ETA as the dash placeholder", () => { const group: ReportIncomingShipGroup = { origin: 99, destination: 17, distance: 80, speed: 0, mass: 4, }; const selection: ShipGroupSelection = { variant: "incoming", group }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect(ui.getByTestId("inspector-ship-group-field-eta")).toHaveTextContent( "—", ); }); test("unidentified group renders coordinates and the no-data hint", () => { const group: ReportUnidentifiedShipGroup = { x: 555.5, y: 222.25 }; const selection: ShipGroupSelection = { variant: "unidentified", group }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); const coords = ui.getByTestId("inspector-ship-group-field-coordinates"); expect(coords).toHaveTextContent("555.5"); expect(coords).toHaveTextContent("222.25"); expect(ui.getByTestId("inspector-ship-group-no-data")).toBeInTheDocument(); }); test("planet name resolves to '#NN' when missing from the planet list", () => { const selection: ShipGroupSelection = { variant: "local", group: localGroup({ destination: 999 }), }; const ui = render(ShipGroup, { props: { selection, planets: PLANETS } }); expect( ui.getByTestId("inspector-ship-group-field-location"), ).toHaveTextContent("#999"); }); });