import { describe, expect, it } from "vitest"; import { dungeonWorldObjectState, nearestDungeonWorldInteraction, validateDungeonWorldObject, type DungeonWorldObjectDefinition, } from "./dungeonWorldObjects"; const door: DungeonWorldObjectDefinition = { id: "test-door", name: "Test Door", kind: "door", position: [3, 0, 0], halfExtents: [1, 2, 0.25], initialState: "closed", states: [ { id: "closed", label: "Closed", visible: true, blocksMovement: true, interactionEnabled: true }, { id: "open", label: "Open", visible: false, blocksMovement: false, interactionEnabled: false }, ], interaction: { prompt: "Open door", range: 4, signalId: "open-test-door", allowedStates: ["closed"], }, }; describe("dungeon world objects", () => { it("resolves authored and fallback object states", () => { expect(dungeonWorldObjectState(door, "open").blocksMovement).toBe(false); expect(dungeonWorldObjectState(door, "missing").id).toBe("closed"); }); it("selects the nearest enabled visible interaction in range and line of sight", () => { const farther = { ...door, id: "far-door", position: [3.5, 0, 0] as const }; expect(nearestDungeonWorldInteraction([farther, door], {}, [0, 0, 0])?.object.id).toBe("test-door"); expect(nearestDungeonWorldInteraction([door], { "test-door": "open" }, [0, 0, 0])).toBeNull(); expect(nearestDungeonWorldInteraction([door], {}, [0, 0, 0], () => false)).toBeNull(); }); it("rejects malformed geometry, state, and interaction contracts", () => { expect(() => validateDungeonWorldObject(door)).not.toThrow(); expect(() => validateDungeonWorldObject({ ...door, halfExtents: [0, 2, 1] })).toThrow("invalid geometry"); expect(() => validateDungeonWorldObject({ ...door, initialState: "missing" })).toThrow("does not define"); expect(() => validateDungeonWorldObject({ ...door, interaction: { ...door.interaction!, range: 0 }, })).toThrow("invalid interaction"); }); });