157 lines
4.4 KiB
TypeScript
157 lines
4.4 KiB
TypeScript
|
|
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"
|
||
|
|
}
|
||
|
|
})
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
});
|