Files
webeditor3d/tests/domain/runtime-project-scheduler.test.ts

157 lines
4.4 KiB
TypeScript
Raw Normal View History

import { describe, expect, it } from "vitest";
import {
createActorControlTargetRef,
createEmptyRuntimeResolvedControlState,
createSetActorPresenceControlEffect
} from "../../src/controls/control-surface";
import {
createEmptyProjectScheduler,
createProjectScheduleRoutine,
createProjectScheduleSelectedDaysSelection
} from "../../src/scheduler/project-scheduler";
import {
applyRuntimeProjectScheduleToControlState,
resolveRuntimeProjectScheduleState
} from "../../src/runtime-three/runtime-project-scheduler";
describe("runtime project scheduler", () => {
it("resolves cross-midnight actor routines and keeps unscheduled actors implicitly active", () => {
const actorTarget = createActorControlTargetRef("actor-night-watch");
const scheduler = createEmptyProjectScheduler();
scheduler.routines["routine-night-watch"] = createProjectScheduleRoutine({
id: "routine-night-watch",
title: "Night Watch",
target: actorTarget,
days: createProjectScheduleSelectedDaysSelection(["monday"]),
startHour: 22,
endHour: 2,
effect: createSetActorPresenceControlEffect({
target: actorTarget,
active: true
})
});
expect(
resolveRuntimeProjectScheduleState({
scheduler,
actorIds: ["actor-night-watch", "actor-always-on"],
dayNumber: 1,
timeOfDayHours: 23
}).actors
).toEqual(
expect.arrayContaining([
expect.objectContaining({
actorId: "actor-night-watch",
hasRules: true,
active: true,
activeRoutineId: "routine-night-watch",
activeRoutineTitle: "Night Watch"
}),
expect.objectContaining({
actorId: "actor-always-on",
hasRules: false,
active: true,
activeRoutineId: null,
activeRoutineTitle: null
})
])
);
expect(
resolveRuntimeProjectScheduleState({
scheduler,
actorIds: ["actor-night-watch"],
dayNumber: 2,
timeOfDayHours: 1.5
}).actors[0]
).toEqual(
expect.objectContaining({
actorId: "actor-night-watch",
active: true,
activeRoutineTitle: "Night Watch"
})
);
expect(
resolveRuntimeProjectScheduleState({
scheduler,
actorIds: ["actor-night-watch"],
dayNumber: 2,
timeOfDayHours: 3
}).actors[0]
).toEqual(
expect.objectContaining({
actorId: "actor-night-watch",
hasRules: true,
active: false,
activeRoutineId: null,
activeRoutineTitle: null
})
);
});
it("prefers the highest-priority active routine and writes actor presence into resolved control state", () => {
const actorTarget = createActorControlTargetRef("actor-market-vendor");
const scheduler = createEmptyProjectScheduler();
scheduler.routines["routine-open"] = createProjectScheduleRoutine({
id: "routine-open",
title: "Open Stall",
target: actorTarget,
startHour: 9,
endHour: 18,
priority: 0,
effect: createSetActorPresenceControlEffect({
target: actorTarget,
active: true
})
});
scheduler.routines["routine-break"] = createProjectScheduleRoutine({
id: "routine-break",
title: "Lunch Break",
target: actorTarget,
startHour: 12,
endHour: 13.5,
priority: 5,
effect: createSetActorPresenceControlEffect({
target: actorTarget,
active: false
})
});
const resolvedSchedule = resolveRuntimeProjectScheduleState({
scheduler,
actorIds: ["actor-market-vendor"],
dayNumber: 1,
timeOfDayHours: 12.25
});
const resolvedControl = applyRuntimeProjectScheduleToControlState(
createEmptyRuntimeResolvedControlState(),
resolvedSchedule
);
expect(resolvedSchedule.actors[0]).toEqual(
expect.objectContaining({
actorId: "actor-market-vendor",
active: false,
activeRoutineId: "routine-break",
activeRoutineTitle: "Lunch Break"
})
);
expect(resolvedControl.discrete).toEqual([
expect.objectContaining({
type: "actorPresence",
target: {
kind: "actor",
actorId: "actor-market-vendor"
},
value: false,
source: {
kind: "scheduler",
scheduleId: "routine-break"
}
})
]);
});
});