Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/integrations/hrSickLeaveService.object-access.test.ts
T

89 lines
3.2 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
audit: vi.fn(),
crypto: {
encrypt: vi.fn(async (_tenantId: string, value: string) => `cipher:${value}`),
decrypt: vi.fn(async (_tenantId: string, value: string) => value.replace("cipher:", "")),
},
tx: {
employeeSickLeaveReport: {
findFirst: vi.fn(),
update: vi.fn(),
},
file: { findFirst: vi.fn() },
fileEntityLink: { upsert: vi.fn() },
},
}));
vi.mock("~/utils/db/.server/tenantRls.server", () => ({
withTenantRLS: (_tenantId: string, callback: (tx: typeof mocks.tx) => unknown) => callback(mocks.tx),
}));
vi.mock("@hivegrid/db/audit-events.server", () => ({ createAuditEvent: mocks.audit }));
vi.mock("./hrFieldCrypto.server", () => ({ getHrFieldCrypto: () => mocks.crypto }));
import {
attachCertificate,
cancelSickLeave,
closeSickLeave,
revealCertificateFileId,
} from "./hrSickLeaveService.server";
const report = {
id: "report-1",
tenantId: "tenant-1",
employeeUserId: "employee-1",
reportedByUserId: "employee-1",
startDate: new Date("2026-07-20"),
expectedReturnDate: null,
returnDate: null,
certificateRefCiphertext: "cipher:file-1",
status: "reported",
note: null,
calendarEventId: null,
createdAt: new Date("2026-07-20"),
updatedAt: new Date("2026-07-20"),
};
describe("sick-leave object access", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.tx.employeeSickLeaveReport.findFirst.mockResolvedValue(report);
mocks.tx.employeeSickLeaveReport.update.mockResolvedValue(report);
mocks.tx.file.findFirst.mockResolvedValue({ id: "file-2" });
mocks.tx.fileEntityLink.upsert.mockResolvedValue({ id: "link-1" });
mocks.audit.mockResolvedValue({ id: "audit-1" });
});
it.each([
["attach", () => attachCertificate({ tenantId: "tenant-1", reportId: "report-1", actorUserId: "other-user", certificateFileId: "file-2", canManageAny: false })],
["reveal", () => revealCertificateFileId({ tenantId: "tenant-1", reportId: "report-1", revealerUserId: "other-user", canManageAny: false })],
["close", () => closeSickLeave({ tenantId: "tenant-1", reportId: "report-1", actorUserId: "other-user", returnDate: new Date("2026-07-22"), canManageAny: false })],
["cancel", () => cancelSickLeave({ tenantId: "tenant-1", reportId: "report-1", actorUserId: "other-user", canManageAny: false })],
])("returns not-found semantics for a foreign report on %s", async (_name, action) => {
await expect(action()).rejects.toThrow();
expect(mocks.tx.employeeSickLeaveReport.update).not.toHaveBeenCalled();
expect(mocks.audit).not.toHaveBeenCalled();
});
it("allows the owner and an explicitly authorised HR writer", async () => {
await expect(
revealCertificateFileId({
tenantId: "tenant-1",
reportId: "report-1",
revealerUserId: "employee-1",
canManageAny: false,
}),
).resolves.toBe("file-1");
await expect(
closeSickLeave({
tenantId: "tenant-1",
reportId: "report-1",
actorUserId: "hr-user",
returnDate: new Date("2026-07-22"),
canManageAny: true,
}),
).resolves.toBeUndefined();
});
});