// Vitest coverage for the "stationed ship groups" subsection of the // planet inspector. The map deliberately hides on-planet groups; this // subsection is the player's view of the fleets in orbit. // // F8-05 (issue #48 п.32) moved the race column from the row into a // dropdown above the table. The dropdown only renders when more than // one race is stationed; it seeds with the player's own race when // local groups are stationed here, otherwise with the first race // alphabetically. Single-race cases skip the dropdown and render // straight through. The race column is dropped in both modes — the // dropdown's value already names the active race. import "@testing-library/jest-dom/vitest"; import { fireEvent, render } from "@testing-library/svelte"; import { beforeEach, describe, expect, test } from "vitest"; import { i18n } from "../src/lib/i18n/index.svelte"; import type { ReportLocalShipGroup, ReportOtherShipGroup, ReportPlanet, } from "../src/api/game-state"; import ShipGroups from "../src/lib/inspectors/planet/ship-groups.svelte"; beforeEach(() => { i18n.resetForTests("en"); }); const HOME_PLANET: 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: 100, production: "Capital", freeIndustry: 1000, }; const FOREIGN_PLANET: ReportPlanet = { ...HOME_PLANET, number: 99, name: "Outpost", kind: "other", owner: "Klingons", }; function localGroup( overrides: Partial = {}, ): ReportLocalShipGroup { return { id: "uuid-1", count: 1, 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, }; } function otherGroup( overrides: Partial = {}, ): ReportOtherShipGroup { return { count: 3, class: "Bird-of-Prey", tech: { drive: 6, weapons: 4, shields: 3, cargo: 0 }, cargo: "NONE", load: 0, destination: 99, origin: null, range: null, speed: 0, mass: 25, ...overrides, }; } describe("planet inspector — stationed ship groups", () => { test("renders one row per in-orbit local group; the dropdown is hidden with a single race", () => { const ui = render(ShipGroups, { props: { planet: HOME_PLANET, localShipGroups: [ localGroup({ id: "g1", count: 2, class: "Frontier", mass: 24 }), localGroup({ id: "g2", count: 7, class: "Furgon", mass: 173.25 }), ], otherShipGroups: [], localRace: "Earthlings", }, }); const rows = ui.getAllByTestId("inspector-planet-ship-groups-row"); expect(rows.length).toBe(2); // Race no longer appears in the row (it is hoisted to the // dropdown — and the dropdown itself is hidden when only one // race is present). expect( ui.queryByTestId("inspector-planet-ship-groups-race-filter"), ).toBeNull(); expect(rows[0]).not.toHaveTextContent("Earthlings"); expect(rows[0]).toHaveTextContent("Frontier"); expect(rows[0]).toHaveTextContent("2"); expect(rows[0]).toHaveTextContent("24"); expect(rows[1]).toHaveTextContent("Furgon"); expect(rows[1]).toHaveTextContent("173.25"); }); test("multiple races surface a dropdown that filters the table", async () => { const ui = render(ShipGroups, { props: { planet: FOREIGN_PLANET, localShipGroups: [ localGroup({ id: "own-1", destination: 99, class: "Frontier" }), ], otherShipGroups: [ otherGroup({ class: "Bird-of-Prey", destination: 99 }), ], localRace: "Earthlings", }, }); const select = ui.getByTestId( "inspector-planet-ship-groups-race-filter", ) as HTMLSelectElement; // Own ships are stationed → own race wins as the default; // alphabetical ordering puts the foreign one second. expect(select.value).toBe("Earthlings"); expect(Array.from(select.options).map((o) => o.value)).toEqual([ "Earthlings", "Klingons", ]); expect( ui.getAllByTestId("inspector-planet-ship-groups-row").length, ).toBe(1); expect( ui.getByTestId("inspector-planet-ship-groups-row"), ).toHaveTextContent("Frontier"); await fireEvent.change(select, { target: { value: "Klingons" } }); const rows = ui.getAllByTestId("inspector-planet-ship-groups-row"); expect(rows.length).toBe(1); expect(rows[0]).toHaveTextContent("Bird-of-Prey"); }); test("with no own ships the dropdown collapses to the single foreign race", () => { const ui = render(ShipGroups, { props: { planet: { ...HOME_PLANET, owner: "Andorians", kind: "other", }, localShipGroups: [], otherShipGroups: [ otherGroup({ class: "Bird-of-Prey", destination: 17 }), ], localRace: "Earthlings", }, }); // Single foreign race → no dropdown. expect( ui.queryByTestId("inspector-planet-ship-groups-race-filter"), ).toBeNull(); expect( ui.getAllByTestId("inspector-planet-ship-groups-row").length, ).toBe(1); }); test("filters out groups stationed on a different planet", () => { const ui = render(ShipGroups, { props: { planet: HOME_PLANET, localShipGroups: [ localGroup({ id: "g1", destination: 17 }), localGroup({ id: "g2", destination: 99 }), ], otherShipGroups: [], localRace: "Earthlings", }, }); expect(ui.getAllByTestId("inspector-planet-ship-groups-row").length).toBe( 1, ); }); test("excludes in-hyperspace groups even when destination matches", () => { const ui = render(ShipGroups, { props: { planet: HOME_PLANET, localShipGroups: [ localGroup({ id: "stationed", destination: 17 }), localGroup({ id: "fleeing", destination: 17, origin: 99, range: 5, }), ], otherShipGroups: [], localRace: "Earthlings", }, }); expect(ui.getAllByTestId("inspector-planet-ship-groups-row").length).toBe( 1, ); }); test("subsection collapses entirely when nothing is stationed", () => { const ui = render(ShipGroups, { props: { planet: HOME_PLANET, localShipGroups: [], otherShipGroups: [], localRace: "Earthlings", }, }); expect(ui.queryByTestId("inspector-planet-ship-groups")).toBeNull(); }); });