import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("@capakraken/application", () => ({ listAssignmentBookings: vi.fn(), })); vi.mock("../router/project-planning-read-model.js", () => ({ loadProjectPlanningReadModel: vi.fn(), })); vi.mock("../router/timeline-project-query-support.js", () => ({ findTimelineProjectOrThrow: vi.fn(), projectShiftContextSelect: { id: true }, timelineProjectContextSelect: { id: true }, })); vi.mock("../router/timeline-shift-planning.js", () => ({ buildTimelineShiftPlan: vi.fn(), })); vi.mock("../router/timeline-project-read-support.js", () => ({ buildTimelineShiftValidationBookings: vi.fn(), })); vi.mock("../router/timeline-read-shared.js", async () => { const actual = await vi.importActual( "../router/timeline-read-shared.js", ); return { ...actual, getAssignmentResourceIds: vi.fn(), }; }); vi.mock("../router/timeline-shift-support.js", () => ({ buildTimelineProjectShiftValidation: vi.fn(), })); import { listAssignmentBookings } from "@capakraken/application"; import { loadProjectPlanningReadModel } from "../router/project-planning-read-model.js"; import { loadProjectShiftContext, loadTimelineProjectContext, previewTimelineProjectShift, } from "../router/timeline-project-load-support.js"; import { findTimelineProjectOrThrow } from "../router/timeline-project-query-support.js"; import { buildTimelineShiftPlan } from "../router/timeline-shift-planning.js"; import { buildTimelineShiftValidationBookings } from "../router/timeline-project-read-support.js"; import { getAssignmentResourceIds } from "../router/timeline-read-shared.js"; import { buildTimelineProjectShiftValidation } from "../router/timeline-shift-support.js"; const findTimelineProjectOrThrowMock = vi.mocked(findTimelineProjectOrThrow); const loadProjectPlanningReadModelMock = vi.mocked(loadProjectPlanningReadModel); const listAssignmentBookingsMock = vi.mocked(listAssignmentBookings); const getAssignmentResourceIdsMock = vi.mocked(getAssignmentResourceIds); const buildTimelineShiftValidationBookingsMock = vi.mocked(buildTimelineShiftValidationBookings); const buildTimelineShiftPlanMock = vi.mocked(buildTimelineShiftPlan); const buildTimelineProjectShiftValidationMock = vi.mocked(buildTimelineProjectShiftValidation); describe("timeline project load support", () => { beforeEach(() => { vi.clearAllMocks(); }); it("loads shift context with booking windows when assignment resources exist", async () => { findTimelineProjectOrThrowMock.mockResolvedValueOnce({ id: "project_1" } as never); loadProjectPlanningReadModelMock.mockResolvedValueOnce({ demandRequirements: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], readModel: { allocations: [], demands: [], assignments: [{ resourceId: "resource_1" }], }, } as never); getAssignmentResourceIdsMock.mockReturnValueOnce(["resource_1"]); listAssignmentBookingsMock.mockResolvedValueOnce([{ id: "booking_1" }] as never); buildTimelineShiftValidationBookingsMock.mockReturnValueOnce([{ id: "window_1" }] as never); buildTimelineShiftPlanMock.mockReturnValueOnce({ shifts: 1 } as never); await expect(loadProjectShiftContext({} as never, "project_1")).resolves.toEqual({ project: { id: "project_1" }, demandRequirements: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], shiftPlan: { shifts: 1 }, }); expect(listAssignmentBookingsMock).toHaveBeenCalledWith({}, { resourceIds: ["resource_1"], }); expect(buildTimelineShiftValidationBookingsMock).toHaveBeenCalledWith([{ id: "booking_1" }]); expect(buildTimelineShiftPlanMock).toHaveBeenCalledWith({ demandRequirements: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], allAssignmentWindows: [{ id: "window_1" }], }); }); it("loads project context and skips booking lookup without assignment resources", async () => { findTimelineProjectOrThrowMock.mockResolvedValueOnce({ id: "project_1", startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-10T00:00:00.000Z"), } as never); loadProjectPlanningReadModelMock.mockResolvedValueOnce({ readModel: { allocations: [{ id: "allocation_1" }], demands: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], }, } as never); getAssignmentResourceIdsMock.mockReturnValueOnce([]); await expect(loadTimelineProjectContext({} as never, "project_1")).resolves.toEqual({ project: { id: "project_1", startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-10T00:00:00.000Z"), }, allocations: [{ id: "allocation_1" }], demands: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], allResourceAllocations: [], resourceIds: [], }); expect(listAssignmentBookingsMock).not.toHaveBeenCalled(); }); it("builds project shift previews from loaded context", async () => { findTimelineProjectOrThrowMock.mockResolvedValueOnce({ id: "project_1" } as never); loadProjectPlanningReadModelMock.mockResolvedValueOnce({ demandRequirements: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], readModel: { allocations: [], demands: [], assignments: [{ resourceId: null }], }, } as never); getAssignmentResourceIdsMock.mockReturnValueOnce([]); buildTimelineShiftPlanMock.mockReturnValueOnce({ shifts: [] } as never); buildTimelineProjectShiftValidationMock.mockReturnValueOnce({ ok: true } as never); await expect( previewTimelineProjectShift({} as never, { projectId: "project_1", newStartDate: new Date("2026-04-02T00:00:00.000Z"), newEndDate: new Date("2026-04-08T00:00:00.000Z"), }), ).resolves.toEqual({ ok: true }); expect(buildTimelineProjectShiftValidationMock).toHaveBeenCalledWith({ context: { project: { id: "project_1" }, demandRequirements: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], shiftPlan: { shifts: [] }, }, newStartDate: new Date("2026-04-02T00:00:00.000Z"), newEndDate: new Date("2026-04-08T00:00:00.000Z"), }); }); });