// Phase 29 component coverage for `lib/active-view/map-toggles.svelte`. // The popover is a thin view of the `GameStateStore` runes — // every checkbox fires `setMapToggle` on the store and reads the // current state through `store.mapToggles`. F8-05 (issue #48 п.8) // dropped the wrap-scrolling radio group from the UI; the // `wrapMode` rune and the renderer's no-wrap path stay put for a // future game-server-side feature flag, but no surface exposes // the choice today. 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.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-planet-names")).toBeChecked(); expect(ui.getByTestId("map-toggles-visible-hyperspace")).toBeChecked(); expect(ui.queryByTestId("map-toggles-wrap-torus")).toBeNull(); expect(ui.queryByTestId("map-toggles-wrap-no-wrap")).toBeNull(); }); 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("planet-names checkbox flips the planetNames toggle (F8-12 / #29)", 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-planet-names")); expect(setMapToggle).toHaveBeenCalledWith("planetNames", false); }); 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(); }); });