refactor(api): extract timeline project load support
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
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<typeof import("../router/timeline-read-shared.js")>(
|
||||
"../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"),
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user