import { useGLTF } from "@react-three/drei"; import { afterEach, describe, expect, it, vi } from "vitest"; import { dungeonGltfUrls } from "./dungeonAssets"; import { dungeonDefinitionById } from "./dungeonRegistry"; import { activateDungeonSession, restartActiveDungeonSession } from "./dungeonSession"; import { usePartyStore } from "./partyStore"; import { useGameStore } from "./store"; import { DEFAULT_MANASTORM_ADMIN_CONFIG } from "./manastormAdminConfig"; import { useManastormAdminStore } from "./manastormAdminStore"; import { SHELVED_MODES_ENABLED } from "../app/releaseFeatures"; import { dungeonEncounterSnapshot, importDungeonEncounterSnapshots, } from "./dungeonEncounterRuntime"; import { WAILING_NARALEX_ENCOUNTER, useWailingEncounterStore } from "./wailingCavernsEncounter"; describe("dungeon session asset eviction", () => { afterEach(() => { vi.restoreAllMocks(); vi.unstubAllEnvs(); useManastormAdminStore.setState({ config: DEFAULT_MANASTORM_ADMIN_CONFIG, draft: DEFAULT_MANASTORM_ADMIN_CONFIG, dirty: false }); useGameStore.getState().activateDungeon("wailing-caverns"); }); it("evicts the previous dungeon before publishing the next session", () => { const previous = dungeonDefinitionById("auchenai-crypts")!; useGameStore.getState().activateDungeon(previous.id); const clear = vi.spyOn(useGLTF, "clear").mockImplementation(() => undefined); expect(activateDungeonSession("wailing-caverns")).toBe(true); expect(clear.mock.calls.map(([url]) => url)).toEqual(dungeonGltfUrls(previous)); expect(useGameStore.getState().activeDungeonId).toBe("wailing-caverns"); }); it("does not evict the active dungeon when the destination is invalid", () => { const clear = vi.spyOn(useGLTF, "clear").mockImplementation(() => undefined); expect(activateDungeonSession("not-a-dungeon")).toBe(false); expect(clear).not.toHaveBeenCalled(); }); it("does not activate a direct production session before its dungeon pack is usable", () => { vi.stubEnv("DEV", false); useGameStore.getState().activateDungeon("wailing-caverns"); const clear = vi.spyOn(useGLTF, "clear").mockImplementation(() => undefined); expect(activateDungeonSession("deadmines")).toBe(false); expect(useGameStore.getState().activeDungeonId).toBe("wailing-caverns"); expect(clear).not.toHaveBeenCalled(); }); it("restarts the active dungeon in place while preserving its party and encounter state", () => { const active = dungeonDefinitionById("wailing-caverns")!; expect(activateDungeonSession(active.id)).toBe(true); usePartyStore.getState().initializeParty("retry-party", 20, 600, "healer"); const members = usePartyStore.getState().members.map((member) => member.id); const current = dungeonEncounterSnapshot(WAILING_NARALEX_ENCOUNTER.id)!; const progressed = { ...current, phase: "ready", revision: current.revision + 1 } as const; expect(importDungeonEncounterSnapshots(active.id, [progressed])).toEqual([ WAILING_NARALEX_ENCOUNTER.id, ]); const revision = useGameStore.getState().sessionRevision; const clear = vi.spyOn(useGLTF, "clear").mockImplementation(() => undefined); expect(restartActiveDungeonSession()).toBe(true); expect(clear.mock.calls.map(([url]) => url)).toEqual(dungeonGltfUrls(active)); expect(useGameStore.getState().sessionRevision).toBe(revision + 1); expect(usePartyStore.getState().members.map((member) => member.id)).toEqual(members); expect(dungeonEncounterSnapshot(WAILING_NARALEX_ENCOUNTER.id)).toMatchObject({ phase: "ready", revision: progressed.revision, }); }); it("applies the published dungeon group anchor at the session boundary", () => { const spawn = { footPosition: [12, 3, -8] as const, yaw: 1.25 }; useManastormAdminStore.setState({ config: { ...DEFAULT_MANASTORM_ADMIN_CONFIG, dungeonSpawns: { "wailing-caverns": spawn } }, }); expect(activateDungeonSession("wailing-caverns")).toBe(true); const definition = dungeonDefinitionById("wailing-caverns")!; expect(useGameStore.getState().activeSpawn).toEqual(SHELVED_MODES_ENABLED ? spawn : { footPosition: definition.entrance.footPosition, yaw: definition.entrance.yaw, }); }); it("hydrates a same-process checkpoint even when the reset revision is newer", () => { const current = dungeonEncounterSnapshot(WAILING_NARALEX_ENCOUNTER.id)!; const saved = { ...current, phase: "ready" } as const; expect(activateDungeonSession("wailing-caverns", "normal", { encounterSnapshots: [saved], })).toBe(true); expect(useWailingEncounterStore.getState().phase).toBe("ready"); }); });