157 行
4.1 KiB
JavaScript
157 行
4.1 KiB
JavaScript
const {
|
|
calculateRequestedDays,
|
|
calculateRequestedDaysByWorkingCalendar,
|
|
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(/参数校验失败/);
|
|
});
|
|
});
|
|
|
|
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(/参数校验失败/);
|
|
});
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|
|
});
|