import { AllocationStatus } from "@capakraken/shared"; import { describe, expect, it } from "vitest"; import { detectOverlaps, validateAvailability } from "../allocation/availability-validator.js"; const stdAvailability = { monday: 8, tuesday: 8, wednesday: 8, thursday: 8, friday: 8, }; describe("validateAvailability", () => { it("passes when no existing allocations", () => { const result = validateAvailability( new Date("2025-01-06"), new Date("2025-01-10"), 8, stdAvailability, [], ); expect(result.valid).toBe(true); expect(result.conflicts).toHaveLength(0); }); it("detects conflict when combined hours exceed availability", () => { const existing = [{ startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10"), hoursPerDay: 6, status: AllocationStatus.CONFIRMED, }]; const result = validateAvailability( new Date("2025-01-06"), new Date("2025-01-10"), 4, // 6+4=10 > 8 stdAvailability, existing, ); expect(result.valid).toBe(false); expect(result.conflicts).toHaveLength(5); // All 5 working days }); it("passes when combined hours exactly match availability", () => { const existing = [{ startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10"), hoursPerDay: 4, status: AllocationStatus.CONFIRMED, }]; const result = validateAvailability( new Date("2025-01-06"), new Date("2025-01-10"), 4, // 4+4=8 ≤ 8 stdAvailability, existing, ); expect(result.valid).toBe(true); }); it("ignores cancelled allocations", () => { const existing = [{ startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10"), hoursPerDay: 8, status: AllocationStatus.CANCELLED, }]; const result = validateAvailability( new Date("2025-01-06"), new Date("2025-01-10"), 8, stdAvailability, existing, ); expect(result.valid).toBe(true); }); it("skips non-working days in conflict check", () => { const result = validateAvailability( new Date("2025-01-04"), // Saturday new Date("2025-01-05"), // Sunday 8, stdAvailability, [], ); expect(result.valid).toBe(true); expect(result.conflicts).toHaveLength(0); }); }); describe("detectOverlaps", () => { const existingAlloc = { id: "alloc-1", startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10"), projectId: "proj-1", status: AllocationStatus.ACTIVE, }; it("detects overlapping allocations", () => { const overlaps = detectOverlaps( new Date("2025-01-08"), new Date("2025-01-15"), [existingAlloc], ); expect(overlaps).toContain("alloc-1"); }); it("returns empty for non-overlapping date ranges", () => { const overlaps = detectOverlaps( new Date("2025-01-13"), // Starts after existing ends new Date("2025-01-17"), [existingAlloc], ); expect(overlaps).toHaveLength(0); }); it("excludes same-project allocations when excludeProjectId provided", () => { const overlaps = detectOverlaps( new Date("2025-01-08"), new Date("2025-01-15"), [existingAlloc], "proj-1", // Exclude this project ); expect(overlaps).toHaveLength(0); }); it("ignores cancelled allocations", () => { const cancelled = { ...existingAlloc, status: AllocationStatus.CANCELLED }; const overlaps = detectOverlaps( new Date("2025-01-08"), new Date("2025-01-15"), [cancelled], ); expect(overlaps).toHaveLength(0); }); });