import { beforeEach, describe, expect, it } from "vitest"; import { DUNGEON_MANIFEST } from "./dungeonManifest"; import { useGameStore } from "./store"; describe("game store", () => { beforeEach(() => { useGameStore.getState().resetAtEntrance(); useGameStore.setState({ overlay: null, paused: false, mapOpen: false, companionOpen: false, assetStatus: "checking", assetMessage: null, distanceTravelled: 0, hasMoved: false, }); }); it("opens the map without leaving camera control active", () => { useGameStore.setState({ cameraLookActive: true }); useGameStore.getState().toggleMap(); expect(useGameStore.getState()).toMatchObject({ overlay: "map", paused: true, mapOpen: true, cameraLookActive: false, }); }); it("keeps all full-screen game panels mutually exclusive", () => { useGameStore.getState().openOverlay("spellbook"); expect(useGameStore.getState()).toMatchObject({ overlay: "spellbook", paused: true, mapOpen: false }); useGameStore.getState().openOverlay("talents"); expect(useGameStore.getState()).toMatchObject({ overlay: "talents", paused: true, mapOpen: false }); useGameStore.getState().openOverlay("bindings"); expect(useGameStore.getState()).toMatchObject({ overlay: "bindings", paused: true, mapOpen: false }); useGameStore.getState().closeOverlay(); expect(useGameStore.getState()).toMatchObject({ overlay: null, paused: false, mapOpen: false }); }); it("blocks camera-drag play while the one-screen companion is open", () => { useGameStore.setState({ cameraLookActive: true }); useGameStore.getState().setCompanionOpen(true); expect(useGameStore.getState()).toMatchObject({ companionOpen: true, cameraLookActive: false }); }); it("records throttled exploration snapshots", () => { useGameStore.getState().updatePlayerSnapshot({ position: [164, -73.66, 132], yaw: -2, distanceDelta: 1.25, }); const state = useGameStore.getState(); expect(state.distanceTravelled).toBeCloseTo(1.25); expect(state.hasMoved).toBe(true); expect(state.areaName).toContain("Entrance"); }); it("keeps a grounded navigation anchor while the physical player is airborne", () => { useGameStore.getState().updatePlayerSnapshot({ position: [164, -73.66, 132], yaw: -2, grounded: true, }); useGameStore.getState().updatePlayerSnapshot({ position: [166, -72.2, 133], yaw: -2, grounded: false, }); expect(useGameStore.getState()).toMatchObject({ playerPosition: [166, -72.2, 133], playerNavigationPosition: [164, -73.66, 132], playerGrounded: false, }); useGameStore.getState().updatePlayerSnapshot({ position: [167, -73.66, 134], yaw: -2, grounded: true, }); expect(useGameStore.getState()).toMatchObject({ playerNavigationPosition: [167, -73.66, 134], playerGrounded: true, }); }); it("reset restores the authoritative transformed entrance", () => { useGameStore.getState().setActionLayer("tertiary"); useGameStore.getState().updatePlayerSnapshot({ position: [0, 0, 0], yaw: 0, distanceDelta: 8 }); useGameStore.getState().resetAtEntrance(); const state = useGameStore.getState(); expect(state.playerPosition).toEqual(DUNGEON_MANIFEST.entrance.footPosition); expect(state.playerNavigationPosition).toEqual(DUNGEON_MANIFEST.entrance.footPosition); expect(state.playerGrounded).toBe(true); expect(state.cameraYaw).toBe(DUNGEON_MANIFEST.entrance.yaw); expect(state.distanceTravelled).toBe(0); expect(state.actionLayer).toBe("primary"); }); it("does not let a late loading effect cover an already-ready scene", () => { useGameStore.getState().setAssetStatus("ready"); useGameStore.getState().setAssetStatus("loading"); expect(useGameStore.getState().assetStatus).toBe("ready"); }); it("does not notify dual-screen subscribers for repeated input state", () => { useGameStore.getState().setCameraLookActive(false); useGameStore.getState().setInputMode("keyboard"); let notifications = 0; const unsubscribe = useGameStore.subscribe(() => { notifications += 1; }); useGameStore.getState().setCameraLookActive(false); useGameStore.getState().setInputMode("keyboard"); expect(notifications).toBe(0); useGameStore.getState().setCameraLookActive(true); expect(notifications).toBe(1); unsubscribe(); }); });