const { calculateRequestedDays, calculateRequestedDaysByWorkingCalendar, calculateRequestedDaysPreviewByWorkingCalendar, leaveRangesOverlap, summarizeLeaveLedgerEntries, } = require("../../../src/services/leave"); describe("Leave Service", () => { describe("calculateRequestedDays", () => { it("supports same-day half-day requests", () => { expect( calculateRequestedDays({ startDate: "2026-03-10", endDate: "2026-03-10", startSession: "am", endSession: "am", }), ).toBe(0.5); expect( calculateRequestedDays({ startDate: "2026-03-10", endDate: "2026-03-10", startSession: "pm", endSession: "pm", }), ).toBe(0.5); }); it("supports cross-day half-day boundaries", () => { expect( calculateRequestedDays({ startDate: "2026-03-10", endDate: "2026-03-12", startSession: "pm", endSession: "am", }), ).toBe(2); }); it("rejects invalid session ranges", () => { expect(() => calculateRequestedDays({ startDate: "2026-03-10", endDate: "2026-03-10", startSession: "pm", endSession: "am", }), ).toThrow(expect.objectContaining({ code: "VALID_001", statusCode: 422, details: { leave: "invalid_range", reasonCode: "leave.leave_invalid_range" } })); }); }); describe("calculateRequestedDaysByWorkingCalendar", () => { it("skips weekend days by default and respects adjusted workdays", () => { expect( calculateRequestedDaysByWorkingCalendar({ startDate: "2026-03-20", endDate: "2026-03-22", startSession: "am", endSession: "pm", calendarDays: [], }), ).toBe(1); expect( calculateRequestedDaysByWorkingCalendar({ startDate: "2026-03-20", endDate: "2026-03-22", startSession: "am", endSession: "pm", calendarDays: [{ date: "2026-03-21", day_type: "adjusted_workday" }], }), ).toBe(2); }); it("skips configured holidays inside a weekday span", () => { expect( calculateRequestedDaysByWorkingCalendar({ startDate: "2026-03-16", endDate: "2026-03-17", startSession: "am", endSession: "pm", calendarDays: [{ date: "2026-03-17", day_type: "holiday" }], }), ).toBe(1); }); it("rejects ranges that become fully non-working after calendar adjustment", () => { expect(() => calculateRequestedDaysByWorkingCalendar({ startDate: "2026-03-21", endDate: "2026-03-22", startSession: "am", endSession: "pm", calendarDays: [], }), ).toThrow(expect.objectContaining({ code: "VALID_001", statusCode: 422, details: { leave: "non_working_range", reasonCode: "leave.leave_non_working_range" } })); }); }); describe("calculateRequestedDaysPreviewByWorkingCalendar", () => { it("returns official holiday counts while excluding holidays from requested days", () => { expect( calculateRequestedDaysPreviewByWorkingCalendar({ startDate: "2026-01-01", endDate: "2026-01-04", startSession: "am", endSession: "pm", calendarDays: [ { date: "2026-01-01", day_type: "holiday" }, { date: "2026-01-02", day_type: "holiday" }, { date: "2026-01-03", day_type: "holiday" }, { date: "2026-01-04", day_type: "adjusted_workday" }, ], }), ).toEqual({ requestedDays: 1, naturalRequestedDays: 4, holidayDayCount: 3, weekendDayCount: 0, adjustedWorkdayCount: 1, calendarApplied: true, isNonWorkingRange: false, }); }); it("keeps half-day precision for adjusted workdays in preview payload", () => { expect( calculateRequestedDaysPreviewByWorkingCalendar({ startDate: "2026-01-03", endDate: "2026-01-04", startSession: "pm", endSession: "am", calendarDays: [ { date: "2026-01-03", day_type: "holiday" }, { date: "2026-01-04", day_type: "adjusted_workday" }, ], }), ).toEqual({ requestedDays: 0.5, naturalRequestedDays: 1, holidayDayCount: 0.5, weekendDayCount: 0, adjustedWorkdayCount: 0.5, calendarApplied: true, isNonWorkingRange: false, }); }); it("returns zero-day preview for fully non-working ranges when explicitly allowed", () => { expect( calculateRequestedDaysPreviewByWorkingCalendar({ startDate: "2026-05-01", endDate: "2026-05-05", startSession: "am", endSession: "pm", allowNonWorkingRange: true, calendarDays: [ { date: "2026-05-01", day_type: "holiday" }, { date: "2026-05-02", day_type: "holiday" }, { date: "2026-05-03", day_type: "holiday" }, { date: "2026-05-04", day_type: "holiday" }, { date: "2026-05-05", day_type: "holiday" }, ], }), ).toEqual({ requestedDays: 0, naturalRequestedDays: 5, holidayDayCount: 5, weekendDayCount: 0, adjustedWorkdayCount: 0, calendarApplied: true, isNonWorkingRange: true, }); }); }); describe("leaveRangesOverlap", () => { it("detects overlapping half-day ranges", () => { expect( leaveRangesOverlap( { startDate: "2026-03-10", endDate: "2026-03-11", startSession: "pm", endSession: "pm", }, { startDate: "2026-03-11", endDate: "2026-03-12", startSession: "am", endSession: "am", }, ), ).toBe(true); }); it("does not flag non-overlapping adjacent ranges", () => { expect( leaveRangesOverlap( { startDate: "2026-03-10", endDate: "2026-03-10", startSession: "am", endSession: "am", }, { startDate: "2026-03-10", endDate: "2026-03-10", startSession: "pm", endSession: "pm", }, ), ).toBe(false); }); }); describe("summarizeLeaveLedgerEntries", () => { it("calculates reserve / consume / release balances correctly", () => { const summary = summarizeLeaveLedgerEntries([ { entry_type: "grant", days: 10 }, { entry_type: "reserve", days: 2.5 }, { entry_type: "release", days: 1 }, { entry_type: "consume", days: 1.5 }, ]); expect(summary.granted).toBe(10); expect(summary.reserved).toBe(1.5); expect(summary.used).toBe(1.5); expect(summary.available).toBe(7); }); }); });