// Phase 29 component coverage for `lib/active-view/map-toggles.svelte`. // The popover is a thin view of the `GameStateStore` runes — // every control fires `setMapToggle` / `setWrapMode` on the store // and reads the current state through `store.mapToggles` / // `store.wrapMode`. The tests assert the wiring, the default // rendering, and the popover lifecycle (open / Escape close). import "@testing-library/jest-dom/vitest"; import { fireEvent, render } from "@testing-library/svelte"; import { beforeEach, describe, expect, test, vi } from "vitest"; import { i18n } from "../src/lib/i18n/index.svelte"; import MapTogglesControl from "../src/lib/active-view/map-toggles.svelte"; import { DEFAULT_MAP_TOGGLES, GameStateStore, } from "../src/lib/game-state.svelte"; function buildStore(): GameStateStore { const store = new GameStateStore(); store.status = "ready"; store.wrapMode = "torus"; store.mapToggles = { ...DEFAULT_MAP_TOGGLES }; return store; } beforeEach(() => { i18n.resetForTests("en"); }); describe("MapTogglesControl", () => { test("trigger renders and the popover is closed by default", () => { const store = buildStore(); const ui = render(MapTogglesControl, { props: { store } }); const trigger = ui.getByTestId("map-toggles-trigger"); expect(trigger).toBeInTheDocument(); expect(trigger).toHaveAttribute("aria-expanded", "false"); // The 44+ px touch-target is enforced through CSS; jsdom does // not parse scoped Svelte styles for `getComputedStyle`, so the // dimension is verified in the Playwright e2e where real // browsers compute the rule. expect(ui.queryByTestId("map-toggles-surface")).toBeNull(); }); test("clicking the trigger opens the popover with defaults applied", async () => { const store = buildStore(); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); const surface = ui.getByTestId("map-toggles-surface"); expect(surface).toBeInTheDocument(); expect(ui.getByTestId("map-toggles-hyperspace-groups")).toBeChecked(); expect(ui.getByTestId("map-toggles-incoming-groups")).toBeChecked(); expect(ui.getByTestId("map-toggles-unidentified-groups")).toBeChecked(); expect(ui.getByTestId("map-toggles-cargo-routes")).toBeChecked(); expect(ui.getByTestId("map-toggles-battle-markers")).toBeChecked(); expect(ui.getByTestId("map-toggles-bombing-markers")).toBeChecked(); expect(ui.getByTestId("map-toggles-foreign-planets")).toBeChecked(); expect(ui.getByTestId("map-toggles-uninhabited-planets")).toBeChecked(); expect(ui.getByTestId("map-toggles-unidentified-planets")).toBeChecked(); expect(ui.getByTestId("map-toggles-unreachable-planets")).toBeChecked(); expect(ui.getByTestId("map-toggles-visible-hyperspace")).toBeChecked(); expect(ui.getByTestId("map-toggles-wrap-torus")).toBeChecked(); expect(ui.getByTestId("map-toggles-wrap-no-wrap")).not.toBeChecked(); }); test("flipping a checkbox calls setMapToggle with the new value", async () => { const store = buildStore(); const setMapToggle = vi .spyOn(store, "setMapToggle") .mockResolvedValue(undefined); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); await fireEvent.click(ui.getByTestId("map-toggles-battle-markers")); expect(setMapToggle).toHaveBeenCalledWith("battleMarkers", false); await fireEvent.click(ui.getByTestId("map-toggles-foreign-planets")); expect(setMapToggle).toHaveBeenCalledWith("foreignPlanets", false); }); test("battle and bombing toggles are independent", async () => { const store = buildStore(); const setMapToggle = vi .spyOn(store, "setMapToggle") .mockResolvedValue(undefined); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); await fireEvent.click(ui.getByTestId("map-toggles-battle-markers")); expect(setMapToggle).toHaveBeenCalledTimes(1); expect(setMapToggle).toHaveBeenCalledWith("battleMarkers", false); // No spillover into bombingMarkers. expect(setMapToggle).not.toHaveBeenCalledWith("bombingMarkers", false); }); test("selecting the no-wrap radio calls setWrapMode", async () => { const store = buildStore(); const setWrapMode = vi .spyOn(store, "setWrapMode") .mockResolvedValue(undefined); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); await fireEvent.click(ui.getByTestId("map-toggles-wrap-no-wrap")); expect(setWrapMode).toHaveBeenCalledWith("no-wrap"); }); test("Escape closes the popover", async () => { const store = buildStore(); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); expect(ui.getByTestId("map-toggles-surface")).toBeInTheDocument(); await fireEvent.keyDown(document, { key: "Escape" }); expect(ui.queryByTestId("map-toggles-surface")).toBeNull(); }); test("clicking outside the popover closes it", async () => { const store = buildStore(); const ui = render(MapTogglesControl, { props: { store } }); await fireEvent.click(ui.getByTestId("map-toggles-trigger")); expect(ui.getByTestId("map-toggles-surface")).toBeInTheDocument(); // Synthetic outside click — fire on document with the trigger // removed from the click target chain. await fireEvent.click(document.body); expect(ui.queryByTestId("map-toggles-surface")).toBeNull(); }); });