refactor(api): extract vacation management support
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { VacationStatus } from "@capakraken/db";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
approvableVacationStatuses,
|
||||
assertVacationApprovable,
|
||||
assertVacationCancelable,
|
||||
assertVacationRejectable,
|
||||
buildApprovedVacationUpdateData,
|
||||
buildRejectedVacationUpdateData,
|
||||
buildVacationStatusUpdateData,
|
||||
canActorCancelVacation,
|
||||
isVacationManagerRole,
|
||||
} from "../router/vacation-management-support.js";
|
||||
|
||||
describe("vacation management support", () => {
|
||||
it("exposes approvable statuses and guards invalid transitions", () => {
|
||||
expect(approvableVacationStatuses).toEqual([
|
||||
VacationStatus.PENDING,
|
||||
VacationStatus.CANCELLED,
|
||||
VacationStatus.REJECTED,
|
||||
]);
|
||||
|
||||
expect(() => assertVacationApprovable(VacationStatus.PENDING)).not.toThrow();
|
||||
expect(() => assertVacationRejectable(VacationStatus.PENDING)).not.toThrow();
|
||||
expect(() => assertVacationCancelable(VacationStatus.PENDING)).not.toThrow();
|
||||
|
||||
expect(() => assertVacationApprovable(VacationStatus.APPROVED)).toThrowError(
|
||||
new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Only PENDING, CANCELLED, or REJECTED vacations can be approved",
|
||||
}),
|
||||
);
|
||||
expect(() => assertVacationRejectable(VacationStatus.APPROVED)).toThrowError(
|
||||
new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Only PENDING vacations can be rejected",
|
||||
}),
|
||||
);
|
||||
expect(() => assertVacationCancelable(VacationStatus.CANCELLED)).toThrowError(
|
||||
new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Already cancelled",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("builds approval, rejection, and generic status payloads", () => {
|
||||
const approvedAt = new Date("2026-02-01T10:00:00.000Z");
|
||||
|
||||
expect(buildApprovedVacationUpdateData({
|
||||
deductionSnapshotWriteData: { deductedDays: 3, deductionSnapshot: { reason: "calendar" } },
|
||||
approvedById: "user_mgr",
|
||||
approvedAt,
|
||||
})).toEqual({
|
||||
status: VacationStatus.APPROVED,
|
||||
rejectionReason: null,
|
||||
deductedDays: 3,
|
||||
deductionSnapshot: { reason: "calendar" },
|
||||
approvedById: "user_mgr",
|
||||
approvedAt,
|
||||
});
|
||||
|
||||
expect(buildRejectedVacationUpdateData({
|
||||
rejectionReason: "Capacity conflict",
|
||||
})).toEqual({
|
||||
status: VacationStatus.REJECTED,
|
||||
rejectionReason: "Capacity conflict",
|
||||
});
|
||||
|
||||
expect(buildVacationStatusUpdateData({
|
||||
status: "APPROVED",
|
||||
note: "Reviewed",
|
||||
approvedById: "user_mgr",
|
||||
approvedAt,
|
||||
})).toEqual({
|
||||
status: "APPROVED",
|
||||
approvedById: "user_mgr",
|
||||
approvedAt,
|
||||
rejectionReason: null,
|
||||
note: "Reviewed",
|
||||
});
|
||||
|
||||
expect(buildVacationStatusUpdateData({
|
||||
status: "CANCELLED",
|
||||
approvedById: "user_mgr",
|
||||
approvedAt,
|
||||
})).toEqual({
|
||||
status: "CANCELLED",
|
||||
});
|
||||
});
|
||||
|
||||
it("captures manager bypass and ownership-based cancellation access", () => {
|
||||
expect(isVacationManagerRole("ADMIN")).toBe(true);
|
||||
expect(isVacationManagerRole("MANAGER")).toBe(true);
|
||||
expect(isVacationManagerRole("USER")).toBe(false);
|
||||
|
||||
expect(canActorCancelVacation({
|
||||
actorId: "user_1",
|
||||
actorRole: "USER",
|
||||
requestedById: "user_1",
|
||||
resourceUserId: "user_2",
|
||||
})).toBe(true);
|
||||
|
||||
expect(canActorCancelVacation({
|
||||
actorId: "user_1",
|
||||
actorRole: "USER",
|
||||
requestedById: "user_2",
|
||||
resourceUserId: "user_1",
|
||||
})).toBe(true);
|
||||
|
||||
expect(canActorCancelVacation({
|
||||
actorId: "user_mgr",
|
||||
actorRole: "MANAGER",
|
||||
requestedById: "user_2",
|
||||
resourceUserId: null,
|
||||
})).toBe(true);
|
||||
|
||||
expect(canActorCancelVacation({
|
||||
actorId: "user_1",
|
||||
actorRole: "USER",
|
||||
requestedById: "user_2",
|
||||
resourceUserId: "user_3",
|
||||
})).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user