From ebabd00624d899777b9c940d0389f9598268798f Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 14 Apr 2026 02:05:47 +0200 Subject: [PATCH] Add tests for project scheduler routines and legacy NPC presence migration --- .../project-document-json.test.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/tests/serialization/project-document-json.test.ts b/tests/serialization/project-document-json.test.ts index 497cf5eb..7d68bd49 100644 --- a/tests/serialization/project-document-json.test.ts +++ b/tests/serialization/project-document-json.test.ts @@ -216,6 +216,35 @@ describe("project document JSON", () => { expect(parseProjectDocumentJson(serializedDocument)).toEqual(document); }); + it("round-trips project scheduler routines bound to actor presence control", () => { + const document = createEmptyProjectDocument({ + name: "Routine Project" + }); + const npc = createNpcEntity({ + id: "entity-npc-vendor", + actorId: "actor-vendor" + }); + + document.scenes[document.activeSceneId].entities[npc.id] = npc; + document.scheduler.routines["routine-vendor-open"] = + createProjectScheduleRoutine({ + id: "routine-vendor-open", + title: "Vendor Open", + target: createActorControlTargetRef(npc.actorId), + startHour: 8, + endHour: 16, + priority: 2, + effect: createSetActorPresenceControlEffect({ + target: createActorControlTargetRef(npc.actorId), + active: true + }) + }); + + expect( + parseProjectDocumentJson(serializeProjectDocument(document)) + ).toEqual(document); + }); + it("migrates pre-path project documents to empty scene path registries", () => { const migratedDocument = parseProjectDocumentJson( JSON.stringify({ @@ -410,6 +439,68 @@ describe("project document JSON", () => { ); }); + it("migrates legacy NPC time-window presence into project scheduler routines", () => { + const legacyNpc = createNpcEntity({ + id: "entity-npc-night-guard", + actorId: "actor-night-guard", + presence: createNpcTimeWindowPresence({ + startHour: 20, + endHour: 4 + }) + }); + + const migratedDocument = parseProjectDocumentJson( + JSON.stringify({ + version: NPC_PRESENCE_SCENE_DOCUMENT_VERSION, + activeSceneId: "scene-main", + scenes: { + "scene-main": { + ...createEmptyProjectScene({ + id: "scene-main", + name: "Main" + }), + entities: { + [legacyNpc.id]: legacyNpc + } + } + }, + materials: createEmptyProjectDocument().materials, + textures: {}, + assets: {} + }) + ); + + expect(migratedDocument.scenes["scene-main"]?.entities[legacyNpc.id]).toEqual( + createNpcEntity({ + ...legacyNpc, + presence: { + mode: "always" + } + }) + ); + expect(migratedDocument.scheduler.routines).toEqual({ + "schedule-routine-scene-main-entity-npc-night-guard": + expect.objectContaining({ + id: "schedule-routine-scene-main-entity-npc-night-guard", + title: legacyNpc.actorId, + startHour: 20, + endHour: 4, + target: { + kind: "actor", + actorId: legacyNpc.actorId + }, + effect: { + type: "setActorPresence", + target: { + kind: "actor", + actorId: legacyNpc.actorId + }, + active: true + } + }) + }); + }); + it("rejects Scene Exit targets that point at a missing Scene Entry", () => { const document = createEmptyProjectDocument({ sceneName: "Outside" }); const targetScene = createEmptyProjectScene({