72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
tx: {
|
|
hrEmployeeProfile: { findFirst: vi.fn(), findMany: vi.fn() },
|
|
hrLocation: { findFirst: vi.fn(), findMany: vi.fn() },
|
|
},
|
|
}));
|
|
|
|
vi.mock("~/utils/db/.server/tenantRls.server", () => ({
|
|
withTenantRLS: (_tenantId: string, callback: (tx: typeof mocks.tx) => unknown) => callback(mocks.tx),
|
|
}));
|
|
|
|
import {
|
|
isHrAudienceVisible,
|
|
listHrAudienceOptions,
|
|
requireHrAudienceViewer,
|
|
requireValidHrAudience,
|
|
} from "./hrAudience.server";
|
|
|
|
describe("HR audience object access", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.tx.hrEmployeeProfile.findFirst.mockResolvedValue(null);
|
|
mocks.tx.hrEmployeeProfile.findMany.mockResolvedValue([]);
|
|
mocks.tx.hrLocation.findFirst.mockResolvedValue(null);
|
|
mocks.tx.hrLocation.findMany.mockResolvedValue([]);
|
|
});
|
|
|
|
it("matches only the viewer's exact team or location", () => {
|
|
const viewer = { team: "Montage Nord", locationId: "location-1" };
|
|
expect(isHrAudienceVisible("all", null, viewer)).toBe(true);
|
|
expect(isHrAudienceVisible("team", "Montage Nord", viewer)).toBe(true);
|
|
expect(isHrAudienceVisible("team", "Montage Süd", viewer)).toBe(false);
|
|
expect(isHrAudienceVisible("location", "location-1", viewer)).toBe(true);
|
|
expect(isHrAudienceVisible("location", "location-2", viewer)).toBe(false);
|
|
});
|
|
|
|
it("returns 404 semantics for a direct audience URL outside the viewer scope", async () => {
|
|
mocks.tx.hrEmployeeProfile.findFirst.mockResolvedValue({ team: "Montage Nord", locationId: "location-1" });
|
|
await expect(
|
|
requireHrAudienceViewer({
|
|
tenantId: "tenant-1",
|
|
userId: "employee-1",
|
|
kind: "team",
|
|
ref: "Montage Süd",
|
|
canManage: false,
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it("rejects an audience reference that does not belong to the tenant", async () => {
|
|
await expect(
|
|
requireValidHrAudience({
|
|
tenantId: "tenant-1",
|
|
kind: "location",
|
|
ref: "foreign-location",
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it("builds named team and location options without exposing raw labels as UI copy", async () => {
|
|
mocks.tx.hrEmployeeProfile.findMany.mockResolvedValue([{ team: "Montage Nord" }, { team: "Service" }]);
|
|
mocks.tx.hrLocation.findMany.mockResolvedValue([{ id: "location-1", name: "Zentrale Köln" }]);
|
|
await expect(listHrAudienceOptions("tenant-1")).resolves.toEqual([
|
|
{ kind: "team", ref: "Montage Nord", label: "Montage Nord" },
|
|
{ kind: "team", ref: "Service", label: "Service" },
|
|
{ kind: "location", ref: "location-1", label: "Zentrale Köln" },
|
|
]);
|
|
});
|
|
});
|