文件
hyb-oa/server/tests/unit/services/leave.test.js
T
wangsli a837912638
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
feat: 完成错误原因合同与付款就绪提示(09-05-error-explainability-payment-readiness)
2026-09-05 19:00:35 +08:00

235 行
6.9 KiB
JavaScript

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);
});
});
});