c58027c034
Replaces the Phase 10 report stub with a scrollable orchestrator that renders every FBS array as a dedicated section (galaxy summary, votes, player status, my/foreign sciences, my/foreign ship classes, battles, bombings, approaching groups, my/foreign/uninhabited/unknown planets, ships in production, cargo routes, my fleets, my/foreign/unidentified ship groups). A sticky table of contents (a <select> on mobile), "back to map" affordance, IntersectionObserver-driven active-section highlight, and SvelteKit Snapshot-based scroll save/restore round out the view. GameReport gains six new fields (players, otherScience, otherShipClass, battleIds, bombings, shipProductions); decodeReport, the synthetic- report loader, the e2e fixture builder, and EMPTY_SHIP_GROUPS extend in lockstep. ~90 new i18n keys land in en + ru together. The legacy-report parser is extended to populate the new sections from the dg/gplus text formats (Your Sciences, <Race> Sciences, <Race> Ship Types, Bombings, Ships In Production). Ships-in-production prod_used is derived through a new pkg/calc.ShipBuildCost helper; the engine's controller.ProduceShip refactors to call the same helper without any behaviour change (engine tests stay unchanged and green). Battles remain in the parser's Skipped list — the legacy text carries no stable per-battle UUID. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
94 lines
4.0 KiB
TypeScript
94 lines
4.0 KiB
TypeScript
// Component tests for the remaining Phase 10 active-view stubs. Each
|
|
// stub renders the localised view title plus the `coming soon` body
|
|
// copy and exposes a stable `data-testid` so later phases can replace
|
|
// the content without renaming the test hook. Phase 17 lit up the
|
|
// ship-classes table and the ship-class designer; Phase 21 lit up
|
|
// the sciences table and the science designer. Their assertions
|
|
// moved to dedicated suites (`table-ship-classes.test.ts`,
|
|
// `designer-ship-class.test.ts`, `table-sciences.test.ts`,
|
|
// `designer-science.test.ts`); the `table.svelte` router still falls
|
|
// back to the stub for the remaining entities (planets, ship-groups,
|
|
// fleets, races) and that fallback is exercised here.
|
|
|
|
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 MapView from "../src/lib/active-view/map.svelte";
|
|
import TableView from "../src/lib/active-view/table.svelte";
|
|
import ReportView from "../src/lib/active-view/report.svelte";
|
|
import BattleView from "../src/lib/active-view/battle.svelte";
|
|
import MailView from "../src/lib/active-view/mail.svelte";
|
|
|
|
beforeEach(() => {
|
|
i18n.resetForTests("en");
|
|
});
|
|
|
|
describe("active-view stubs", () => {
|
|
test("map view renders loading overlay when no game-state context is provided", () => {
|
|
// The live integration in `lib/active-view/map.svelte` (Phase 11)
|
|
// reads its data from a `GameStateStore` provided through context
|
|
// by `routes/games/[id]/+layout.svelte`. Without the context the
|
|
// store reference is `undefined` and the view stays in the
|
|
// `idle` branch, surfacing the localised loading overlay so the
|
|
// shell never renders an empty active-view slot.
|
|
const ui = render(MapView);
|
|
const node = ui.getByTestId("active-view-map");
|
|
expect(node).toHaveAttribute("data-status", "idle");
|
|
expect(ui.getByTestId("map-loading")).toBeInTheDocument();
|
|
expect(ui.getByTestId("map-canvas-wrap")).toBeInTheDocument();
|
|
});
|
|
|
|
test("table stub falls back for not-yet-implemented entities", () => {
|
|
const ui = render(TableView, { props: { entity: "planets" } });
|
|
const node = ui.getByTestId("active-view-table");
|
|
expect(node).toHaveAttribute("data-entity", "planets");
|
|
expect(node).toHaveTextContent("planets");
|
|
expect(node).toHaveTextContent("coming soon");
|
|
});
|
|
|
|
test("table stub also handles multi-word entities", () => {
|
|
const ui = render(TableView, { props: { entity: "ship-groups" } });
|
|
const node = ui.getByTestId("active-view-table");
|
|
expect(node).toHaveAttribute("data-entity", "ship-groups");
|
|
expect(node).toHaveTextContent("ship groups");
|
|
});
|
|
|
|
test("report view mounts with the TOC and the back-to-map link", () => {
|
|
// Phase 23 replaces the Phase 10 stub with the full report
|
|
// orchestrator. The orchestrator mounts the table of contents
|
|
// regardless of report state; the inner sections render
|
|
// loading copy until a `RenderedReportSource` lands via
|
|
// context. This test only smokes the orchestrator scaffold —
|
|
// per-section assertions live in `report-section-*.test.ts`.
|
|
const r = render(ReportView);
|
|
expect(r.getByTestId("active-view-report")).toBeInTheDocument();
|
|
expect(r.getByTestId("report-toc")).toBeInTheDocument();
|
|
expect(r.getByTestId("report-back-to-map")).toBeInTheDocument();
|
|
});
|
|
|
|
test("mail stub renders its localised title", () => {
|
|
const m = render(MailView);
|
|
expect(m.getByTestId("active-view-mail")).toHaveTextContent(
|
|
"diplomatic mail",
|
|
);
|
|
});
|
|
|
|
test("battle stub stamps the battleId on the host element", () => {
|
|
const ui = render(BattleView, { props: { battleId: "b-42" } });
|
|
const node = ui.getByTestId("active-view-battle");
|
|
expect(node).toHaveAttribute("data-battle-id", "b-42");
|
|
expect(node).toHaveTextContent("battle log");
|
|
});
|
|
|
|
test("battle stub accepts an empty battleId for the list URL", () => {
|
|
const ui = render(BattleView, { props: { battleId: "" } });
|
|
expect(ui.getByTestId("active-view-battle")).toHaveAttribute(
|
|
"data-battle-id",
|
|
"",
|
|
);
|
|
});
|
|
});
|