Files
CapaKraken/packages/api/src/__tests__/timeline-shift-mutation-support.test.ts
T

151 lines
4.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
const { calculateAllocationMock } = vi.hoisted(() => ({
calculateAllocationMock: vi.fn(),
}));
vi.mock("@capakraken/engine", async (importOriginal) => {
const actual = await importOriginal<typeof import("@capakraken/engine")>();
return {
...actual,
calculateAllocation: calculateAllocationMock,
};
});
import {
buildTimelineProjectDateRangeUpdate,
buildTimelineProjectShiftAuditChanges,
buildTimelineShiftedAssignmentUpdate,
recalculateShiftedAssignmentDailyCost,
} from "../router/timeline-shift-mutation-support.js";
describe("timeline shift mutation support", () => {
it("builds shared date range updates for project and demand records", () => {
expect(
buildTimelineProjectDateRangeUpdate({
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
}),
).toEqual({
startDate: new Date("2026-04-03T00:00:00.000Z"),
endDate: new Date("2026-04-12T00:00:00.000Z"),
});
});
it("builds assignment updates with optional recalculated daily cost", () => {
expect(
buildTimelineShiftedAssignmentUpdate({
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
dailyCostCents: 54321,
}),
).toEqual({
startDate: new Date("2026-04-03T00:00:00.000Z"),
endDate: new Date("2026-04-12T00:00:00.000Z"),
dailyCostCents: 54321,
});
expect(
buildTimelineShiftedAssignmentUpdate({
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
dailyCostCents: undefined,
}),
).toEqual({
startDate: new Date("2026-04-03T00:00:00.000Z"),
endDate: new Date("2026-04-12T00:00:00.000Z"),
});
});
it("builds project shift audit payloads", () => {
expect(
buildTimelineProjectShiftAuditChanges({
project: {
id: "project_1",
budgetCents: 200_000,
winProbability: 80,
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-10T00:00:00.000Z"),
},
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
validation: {
valid: true,
errors: [],
warnings: [],
conflictDetails: [],
costImpact: {
currentTotalCents: 100_000,
newTotalCents: 112_000,
deltaCents: 12_000,
budgetCents: 200_000,
budgetUtilizationBefore: 50,
budgetUtilizationAfter: 56,
wouldExceedBudget: false,
},
},
}),
).toEqual({
before: {
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-10T00:00:00.000Z"),
},
after: {
startDate: new Date("2026-04-03T00:00:00.000Z"),
endDate: new Date("2026-04-12T00:00:00.000Z"),
},
costImpact: {
currentTotalCents: 100_000,
newTotalCents: 112_000,
deltaCents: 12_000,
budgetCents: 200_000,
budgetUtilizationBefore: 50,
budgetUtilizationAfter: 56,
wouldExceedBudget: false,
},
});
});
it("recalculates daily cost only for staffed assignments", async () => {
calculateAllocationMock.mockReturnValueOnce({ dailyCostCents: 54321 });
await expect(
recalculateShiftedAssignmentDailyCost({
db: {
vacation: { findMany: vi.fn().mockResolvedValue([]) },
calculationRule: { findMany: vi.fn().mockResolvedValue([{ id: "rule_1" }]) },
} as never,
assignment: {
resourceId: "resource_1",
hoursPerDay: 8,
metadata: { includeSaturday: true },
resource: {
lcrCents: 5_000,
availability: {
monday: 8,
tuesday: 8,
wednesday: 8,
thursday: 8,
friday: 8,
},
},
} as never,
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
}),
).resolves.toBe(54321);
await expect(
recalculateShiftedAssignmentDailyCost({
db: {} as never,
assignment: {
resourceId: null,
resource: null,
} as never,
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
}),
).resolves.toBeUndefined();
});
});