175 lines
5.3 KiB
TypeScript
175 lines
5.3 KiB
TypeScript
import { TRPCError } from "@trpc/server";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
assertTimelineDateRangeValid,
|
|
buildTimelineAllocationEntryUpdate,
|
|
buildTimelineAllocationMetadata,
|
|
buildTimelineBatchShiftAuditChanges,
|
|
buildTimelineQuickAssignAssignmentInput,
|
|
buildTimelineQuickAssignMetadata,
|
|
calculateTimelineAllocationPercentage,
|
|
shiftTimelineAllocationWindow,
|
|
validateTimelineAllocationDateRanges,
|
|
} from "../router/timeline-allocation-mutation-support.js";
|
|
|
|
describe("timeline allocation mutation support", () => {
|
|
it("preserves existing metadata while updating includeSaturday", () => {
|
|
const result = buildTimelineAllocationMetadata({
|
|
existingMetadata: {
|
|
recurrence: { frequency: "weekly", interval: 2 },
|
|
includeSaturday: false,
|
|
},
|
|
includeSaturday: true,
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
metadata: {
|
|
recurrence: { frequency: "weekly", interval: 2 },
|
|
includeSaturday: true,
|
|
},
|
|
includeSaturday: true,
|
|
});
|
|
});
|
|
|
|
it("rejects inverted date ranges", () => {
|
|
expect(() =>
|
|
assertTimelineDateRangeValid(
|
|
new Date("2026-04-10T00:00:00.000Z"),
|
|
new Date("2026-04-09T00:00:00.000Z"),
|
|
)).toThrowError(TRPCError);
|
|
});
|
|
|
|
it("rounds allocation percentages and clamps them to 100", () => {
|
|
expect(calculateTimelineAllocationPercentage(3.9)).toBe(49);
|
|
expect(calculateTimelineAllocationPercentage(9)).toBe(100);
|
|
});
|
|
|
|
it("builds source metadata for quick assign operations", () => {
|
|
expect(buildTimelineQuickAssignMetadata("quickAssign")).toEqual({ source: "quickAssign" });
|
|
expect(buildTimelineQuickAssignMetadata("batchQuickAssign")).toEqual({ source: "batchQuickAssign" });
|
|
});
|
|
|
|
it("builds assignment create payloads for quick assign flows", () => {
|
|
expect(
|
|
buildTimelineQuickAssignAssignmentInput({
|
|
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: 6,
|
|
role: "Engineer",
|
|
roleId: "role_1",
|
|
status: "PROPOSED",
|
|
source: "quickAssign",
|
|
}),
|
|
).toEqual({
|
|
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: 6,
|
|
percentage: 75,
|
|
role: "Engineer",
|
|
roleId: "role_1",
|
|
status: "PROPOSED",
|
|
metadata: { source: "quickAssign" },
|
|
});
|
|
});
|
|
|
|
it("shifts and clamps allocation windows for each batch-shift mode", () => {
|
|
expect(
|
|
shiftTimelineAllocationWindow({
|
|
startDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
daysDelta: 2,
|
|
mode: "move",
|
|
}),
|
|
).toEqual({
|
|
startDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-14T00:00:00.000Z"),
|
|
});
|
|
|
|
expect(
|
|
shiftTimelineAllocationWindow({
|
|
startDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
daysDelta: 5,
|
|
mode: "resize-start",
|
|
}),
|
|
).toEqual({
|
|
startDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
});
|
|
|
|
expect(
|
|
shiftTimelineAllocationWindow({
|
|
startDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
daysDelta: -5,
|
|
mode: "resize-end",
|
|
}),
|
|
).toEqual({
|
|
startDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
});
|
|
});
|
|
|
|
it("builds batch-shift audit payloads", () => {
|
|
expect(
|
|
buildTimelineBatchShiftAuditChanges({
|
|
mode: "move",
|
|
daysDelta: 3,
|
|
count: 2,
|
|
}),
|
|
).toEqual({
|
|
operation: "batchShift",
|
|
mode: "move",
|
|
daysDelta: 3,
|
|
count: 2,
|
|
});
|
|
});
|
|
|
|
it("validates date ranges in bulk", () => {
|
|
expect(() =>
|
|
validateTimelineAllocationDateRanges([
|
|
{
|
|
startDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-11T00:00:00.000Z"),
|
|
},
|
|
{
|
|
startDate: new Date("2026-04-12T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-09T00:00:00.000Z"),
|
|
},
|
|
])).toThrowError(TRPCError);
|
|
});
|
|
|
|
it("builds shared update payloads for demand and assignment changes", () => {
|
|
expect(
|
|
buildTimelineAllocationEntryUpdate({
|
|
hoursPerDay: 7.5,
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
metadata: { includeSaturday: true },
|
|
dailyCostCents: 48000,
|
|
role: "Architect",
|
|
}),
|
|
).toEqual({
|
|
demandRequirementUpdate: {
|
|
hoursPerDay: 7.5,
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
metadata: { includeSaturday: true },
|
|
role: "Architect",
|
|
},
|
|
assignmentUpdate: {
|
|
hoursPerDay: 7.5,
|
|
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
|
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
|
dailyCostCents: 48000,
|
|
metadata: { includeSaturday: true },
|
|
role: "Architect",
|
|
},
|
|
});
|
|
});
|
|
});
|