Files
CapaKraken/packages/api/src/__tests__/vacation-management-support.test.ts
T

127 lines
3.7 KiB
TypeScript

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