89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
tx: {
|
|
hrEmployeeProfile: { findMany: vi.fn() },
|
|
employeeVacationRequest: { findMany: vi.fn() },
|
|
employeeSickLeaveReport: { findMany: vi.fn() },
|
|
},
|
|
}));
|
|
|
|
vi.mock("~/utils/db/.server/tenantRls.server", () => ({
|
|
withTenantRLS: async (_tenantId: string, callback: (tx: typeof mocks.tx) => Promise<unknown>) => callback(mocks.tx),
|
|
}));
|
|
|
|
import { listApprovedAbsencesForRange, listApprovedAbsencesForTeamRange } from "./hrLeaveService.server";
|
|
|
|
describe("approved absence range queries", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.tx.employeeVacationRequest.findMany.mockResolvedValue([]);
|
|
mocks.tx.employeeSickLeaveReport.findMany.mockResolvedValue([]);
|
|
mocks.tx.hrEmployeeProfile.findMany.mockResolvedValue([]);
|
|
});
|
|
|
|
it("filters closed sick-leave history in SQL instead of scanning it in memory", async () => {
|
|
const from = new Date("2026-07-01T00:00:00.000Z");
|
|
const to = new Date("2026-07-31T23:59:59.999Z");
|
|
|
|
await listApprovedAbsencesForRange("tenant-a", from, to);
|
|
|
|
expect(mocks.tx.employeeSickLeaveReport.findMany).toHaveBeenCalledWith({
|
|
where: {
|
|
tenantId: "tenant-a",
|
|
status: { not: "cancelled" },
|
|
startDate: { lte: to },
|
|
OR: [
|
|
{ returnDate: { gte: from } },
|
|
{ returnDate: null, expectedReturnDate: { gte: from } },
|
|
{ returnDate: null, expectedReturnDate: null, startDate: { gte: from } },
|
|
],
|
|
},
|
|
select: { id: true, employeeUserId: true, startDate: true, returnDate: true, expectedReturnDate: true },
|
|
});
|
|
});
|
|
|
|
it("limits the team feed to direct reports in SQL", async () => {
|
|
mocks.tx.hrEmployeeProfile.findMany.mockResolvedValue([{ userId: "employee-a" }, { userId: "employee-b" }]);
|
|
const from = new Date("2026-07-01T00:00:00.000Z");
|
|
const to = new Date("2026-07-31T23:59:59.999Z");
|
|
|
|
await listApprovedAbsencesForTeamRange({
|
|
tenantId: "tenant-a",
|
|
viewerUserId: "manager-a",
|
|
canReadAll: false,
|
|
from,
|
|
to,
|
|
});
|
|
|
|
expect(mocks.tx.hrEmployeeProfile.findMany).toHaveBeenCalledWith({
|
|
where: { tenantId: "tenant-a", managerUserId: "manager-a" },
|
|
select: { userId: true },
|
|
});
|
|
expect(mocks.tx.employeeVacationRequest.findMany).toHaveBeenCalledWith({
|
|
where: {
|
|
tenantId: "tenant-a",
|
|
employeeUserId: { in: ["employee-a", "employee-b"] },
|
|
status: "approved",
|
|
startDate: { lte: to },
|
|
endDate: { gte: from },
|
|
},
|
|
select: { id: true, employeeUserId: true, startDate: true, endDate: true, requestKind: true },
|
|
});
|
|
});
|
|
|
|
it("returns no team absence without querying tenant-wide rows when no direct reports exist", async () => {
|
|
await expect(
|
|
listApprovedAbsencesForTeamRange({
|
|
tenantId: "tenant-a",
|
|
viewerUserId: "manager-a",
|
|
canReadAll: false,
|
|
from: new Date("2026-07-01T00:00:00.000Z"),
|
|
to: new Date("2026-07-31T23:59:59.999Z"),
|
|
}),
|
|
).resolves.toEqual([]);
|
|
expect(mocks.tx.employeeVacationRequest.findMany).not.toHaveBeenCalled();
|
|
expect(mocks.tx.employeeSickLeaveReport.findMany).not.toHaveBeenCalled();
|
|
});
|
|
});
|