257 lines
8.3 KiB
TypeScript
257 lines
8.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("../sse/event-bus.js", () => ({
|
|
emitAllocationCreated: vi.fn(),
|
|
emitAllocationDeleted: vi.fn(),
|
|
emitAllocationUpdated: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../router/timeline-allocation-assignment-procedure-support.js", () => ({
|
|
createTimelineBatchQuickAssignments: vi.fn(),
|
|
createTimelineQuickAssignment: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../router/timeline-allocation-inline-support.js", () => ({
|
|
applyTimelineInlineAllocationUpdate: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../router/timeline-allocation-fragment-support.js", () => ({
|
|
carveTimelineAllocationRange: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../router/timeline-allocation-procedure-support.js", () => ({
|
|
shiftTimelineAllocations: vi.fn(),
|
|
}));
|
|
|
|
import {
|
|
emitAllocationCreated,
|
|
emitAllocationDeleted,
|
|
emitAllocationUpdated,
|
|
} from "../sse/event-bus.js";
|
|
import { carveTimelineAllocationRange } from "../router/timeline-allocation-fragment-support.js";
|
|
import {
|
|
createTimelineBatchQuickAssignments,
|
|
createTimelineQuickAssignment,
|
|
} from "../router/timeline-allocation-assignment-procedure-support.js";
|
|
import { applyTimelineInlineAllocationUpdate } from "../router/timeline-allocation-inline-support.js";
|
|
import { shiftTimelineAllocations } from "../router/timeline-allocation-procedure-support.js";
|
|
import {
|
|
applyTimelineAllocationBatchShiftMutation,
|
|
carveTimelineAllocationRangeMutation,
|
|
createTimelineBatchQuickAssignMutation,
|
|
createTimelineQuickAssignMutation,
|
|
updateTimelineAllocationInlineMutation,
|
|
} from "../router/timeline-allocation-router-support.js";
|
|
|
|
const emitAllocationCreatedMock = vi.mocked(emitAllocationCreated);
|
|
const emitAllocationDeletedMock = vi.mocked(emitAllocationDeleted);
|
|
const emitAllocationUpdatedMock = vi.mocked(emitAllocationUpdated);
|
|
const carveTimelineAllocationRangeMock = vi.mocked(carveTimelineAllocationRange);
|
|
const createTimelineBatchQuickAssignmentsMock = vi.mocked(createTimelineBatchQuickAssignments);
|
|
const createTimelineQuickAssignmentMock = vi.mocked(createTimelineQuickAssignment);
|
|
const applyTimelineInlineAllocationUpdateMock = vi.mocked(applyTimelineInlineAllocationUpdate);
|
|
const shiftTimelineAllocationsMock = vi.mocked(shiftTimelineAllocations);
|
|
|
|
describe("timeline allocation router support", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("updates an inline allocation and emits an update event", async () => {
|
|
const db = {} as never;
|
|
applyTimelineInlineAllocationUpdateMock.mockResolvedValueOnce({
|
|
id: "allocation_1",
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
} as never);
|
|
|
|
await expect(
|
|
updateTimelineAllocationInlineMutation({
|
|
db,
|
|
allocationId: "allocation_1",
|
|
hoursPerDay: 8,
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
includeSaturday: true,
|
|
role: "Lead",
|
|
}),
|
|
).resolves.toEqual({
|
|
id: "allocation_1",
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
|
|
expect(applyTimelineInlineAllocationUpdateMock).toHaveBeenCalledWith({
|
|
db,
|
|
allocationId: "allocation_1",
|
|
hoursPerDay: 8,
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
includeSaturday: true,
|
|
role: "Lead",
|
|
});
|
|
expect(emitAllocationUpdatedMock).toHaveBeenCalledWith({
|
|
id: "allocation_1",
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
});
|
|
|
|
it("creates a quick assignment with the router source metadata", async () => {
|
|
const db = {} as never;
|
|
createTimelineQuickAssignmentMock.mockResolvedValueOnce({ id: "allocation_1" } as never);
|
|
|
|
await expect(
|
|
createTimelineQuickAssignMutation(db, {
|
|
resourceId: "resource_1",
|
|
projectId: "project_1",
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
hoursPerDay: 8,
|
|
role: "Lead",
|
|
status: "PROPOSED",
|
|
}),
|
|
).resolves.toEqual({ id: "allocation_1" });
|
|
|
|
expect(createTimelineQuickAssignmentMock).toHaveBeenCalledWith(db, {
|
|
resourceId: "resource_1",
|
|
projectId: "project_1",
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
hoursPerDay: 8,
|
|
role: "Lead",
|
|
status: "PROPOSED",
|
|
source: "quickAssign",
|
|
});
|
|
});
|
|
|
|
it("maps batch quick assignments to the batch router source metadata", async () => {
|
|
const db = {} as never;
|
|
createTimelineBatchQuickAssignmentsMock.mockResolvedValueOnce({ count: 2 } as never);
|
|
|
|
await expect(
|
|
createTimelineBatchQuickAssignMutation(db, {
|
|
assignments: [
|
|
{
|
|
resourceId: "resource_1",
|
|
projectId: "project_1",
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
hoursPerDay: 8,
|
|
role: "Lead",
|
|
status: "PROPOSED",
|
|
},
|
|
{
|
|
resourceId: "resource_2",
|
|
projectId: "project_2",
|
|
startDate: new Date("2026-04-06T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
hoursPerDay: 6,
|
|
role: "Artist",
|
|
status: "PROPOSED",
|
|
},
|
|
],
|
|
}),
|
|
).resolves.toEqual({ count: 2 });
|
|
|
|
expect(createTimelineBatchQuickAssignmentsMock).toHaveBeenCalledWith(db, {
|
|
assignments: [
|
|
{
|
|
resourceId: "resource_1",
|
|
projectId: "project_1",
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
|
hoursPerDay: 8,
|
|
role: "Lead",
|
|
status: "PROPOSED",
|
|
source: "batchQuickAssign",
|
|
},
|
|
{
|
|
resourceId: "resource_2",
|
|
projectId: "project_2",
|
|
startDate: new Date("2026-04-06T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
hoursPerDay: 6,
|
|
role: "Artist",
|
|
status: "PROPOSED",
|
|
source: "batchQuickAssign",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it("delegates allocation batch shifts unchanged", async () => {
|
|
const db = {} as never;
|
|
shiftTimelineAllocationsMock.mockResolvedValueOnce({ count: 3 } as never);
|
|
|
|
await expect(
|
|
applyTimelineAllocationBatchShiftMutation(db, {
|
|
allocationIds: ["allocation_1", "allocation_2"],
|
|
daysDelta: 5,
|
|
mode: "preserve-duration",
|
|
}),
|
|
).resolves.toEqual({ count: 3 });
|
|
|
|
expect(shiftTimelineAllocationsMock).toHaveBeenCalledWith(db, {
|
|
allocationIds: ["allocation_1", "allocation_2"],
|
|
daysDelta: 5,
|
|
mode: "preserve-duration",
|
|
});
|
|
});
|
|
|
|
it("carves an allocation range and emits update/create/delete events for every affected fragment", async () => {
|
|
const db = {} as never;
|
|
const startDate = new Date("2026-04-09T00:00:00.000Z");
|
|
const endDate = new Date("2026-04-10T00:00:00.000Z");
|
|
|
|
carveTimelineAllocationRangeMock.mockResolvedValueOnce({
|
|
action: "split",
|
|
allocationGroupId: "group_1",
|
|
updatedAllocationIds: ["allocation_left"],
|
|
createdAllocationIds: ["allocation_right"],
|
|
deletedAllocationIds: ["allocation_removed"],
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
|
|
await expect(
|
|
carveTimelineAllocationRangeMutation({
|
|
db,
|
|
allocationId: "allocation_1",
|
|
startDate,
|
|
endDate,
|
|
}),
|
|
).resolves.toEqual({
|
|
action: "split",
|
|
allocationGroupId: "group_1",
|
|
updatedAllocationIds: ["allocation_left"],
|
|
createdAllocationIds: ["allocation_right"],
|
|
deletedAllocationIds: ["allocation_removed"],
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
|
|
expect(carveTimelineAllocationRangeMock).toHaveBeenCalledWith({
|
|
db,
|
|
allocationId: "allocation_1",
|
|
startDate,
|
|
endDate,
|
|
});
|
|
expect(emitAllocationUpdatedMock).toHaveBeenCalledWith({
|
|
id: "allocation_left",
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
expect(emitAllocationCreatedMock).toHaveBeenCalledWith({
|
|
id: "allocation_right",
|
|
projectId: "project_1",
|
|
resourceId: "resource_1",
|
|
});
|
|
expect(emitAllocationDeletedMock).toHaveBeenCalledWith(
|
|
"allocation_removed",
|
|
"project_1",
|
|
"resource_1",
|
|
);
|
|
});
|
|
});
|