108 行
4.3 KiB
JavaScript
108 行
4.3 KiB
JavaScript
const {
|
|
buildReadableReimbursementWhere,
|
|
canReadReimbursementBusinessFact,
|
|
} = require("../../../src/services/reimbursementVisibility");
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const ACTOR_ID = "11111111-1111-4111-8111-111111111111";
|
|
const OTHER_ID = "22222222-2222-4222-8222-222222222222";
|
|
const REIMBURSEMENT_ID = "33333333-3333-4333-8333-333333333333";
|
|
|
|
describe("reimbursement visibility", () => {
|
|
it.each([
|
|
["global finance", ["finance"], {}],
|
|
["global finance manager", ["finance_mgr"], {}],
|
|
["global ceo", ["ceo"], {}],
|
|
["global hr", ["hr"], {}],
|
|
["global admin", ["admin"], {}],
|
|
[
|
|
"manager team",
|
|
["manager"],
|
|
{
|
|
OR: [
|
|
{ owner_id: ACTOR_ID },
|
|
{ submitter_id: ACTOR_ID },
|
|
{ owner: { direct_manager_id: ACTOR_ID } },
|
|
],
|
|
},
|
|
],
|
|
])("keeps the existing %s scope while adding the business-fact filter", (_label, roleCodes, expectedScope) => {
|
|
expect(buildReadableReimbursementWhere({
|
|
employee: { id: ACTOR_ID, roleCodes },
|
|
scope: "all",
|
|
filters: { status: "draft" },
|
|
})).toEqual({
|
|
AND: [
|
|
expectedScope,
|
|
{
|
|
OR: [
|
|
{ status: { not: "draft" } },
|
|
{ owner_id: ACTOR_ID },
|
|
{ submitter_id: ACTOR_ID },
|
|
{ workflow_instances: { some: {} } },
|
|
],
|
|
},
|
|
{ status: "draft" },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("keeps own scope independent from workflow history", () => {
|
|
expect(buildReadableReimbursementWhere({
|
|
employee: { id: ACTOR_ID, roleCodes: ["employee"] },
|
|
scope: "own",
|
|
filters: { status: "draft" },
|
|
})).toEqual({
|
|
AND: [
|
|
{ OR: [{ owner_id: ACTOR_ID }, { submitter_id: ACTOR_ID }] },
|
|
{ status: "draft" },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("keeps every reimbursement read surface on the shared visibility contract", () => {
|
|
const routesDir = path.resolve(__dirname, "../../../src/routes");
|
|
const reimbursementsSource = fs.readFileSync(path.join(routesDir, "reimbursements.js"), "utf8");
|
|
const searchSource = fs.readFileSync(path.join(routesDir, "search.js"), "utf8");
|
|
const exportsSource = fs.readFileSync(path.join(routesDir, "exports.js"), "utf8");
|
|
const dashboardSource = fs.readFileSync(path.join(routesDir, "dashboard.js"), "utf8");
|
|
|
|
expect(reimbursementsSource).toContain("await ensureOwnOrCanViewAll(fastify, request, reimbursement)");
|
|
expect(reimbursementsSource.match(/await ensureOwnCanViewAllOrWorkflowReviewer\(fastify, request/g)).toHaveLength(4);
|
|
expect(reimbursementsSource).toContain("buildReadableReimbursementWhere({");
|
|
expect(reimbursementsSource).toContain("EXISTS (");
|
|
expect(searchSource).toContain("buildReadableReimbursementWhere({");
|
|
expect(exportsSource.match(/buildReadableReimbursementWhere\(\{/g)).toHaveLength(2);
|
|
expect(dashboardSource).toContain("buildReadableReimbursementWhere({");
|
|
});
|
|
|
|
it.each([
|
|
["owner draft", { owner_id: ACTOR_ID, submitter_id: OTHER_ID, status: "draft" }, null, true],
|
|
["submitter draft", { owner_id: OTHER_ID, submitter_id: ACTOR_ID, status: "draft" }, null, true],
|
|
["other approved", { owner_id: OTHER_ID, submitter_id: OTHER_ID, status: "approved" }, null, true],
|
|
["other returned draft", { owner_id: OTHER_ID, submitter_id: OTHER_ID, status: "draft" }, { id: "returned" }, true],
|
|
["other withdrawn draft", { owner_id: OTHER_ID, submitter_id: OTHER_ID, status: "draft" }, { id: "cancelled" }, true],
|
|
["other never-submitted draft", { owner_id: OTHER_ID, submitter_id: OTHER_ID, status: "draft" }, null, false],
|
|
])("classifies %s", async (_label, record, workflowInstance, expected) => {
|
|
const prisma = {
|
|
reimbursementForm: { findUnique: vi.fn() },
|
|
workflowInstance: { findFirst: vi.fn().mockResolvedValue(workflowInstance) },
|
|
};
|
|
|
|
await expect(canReadReimbursementBusinessFact(prisma, {
|
|
id: REIMBURSEMENT_ID,
|
|
...record,
|
|
}, ACTOR_ID)).resolves.toBe(expected);
|
|
|
|
if (record.status === "draft" && record.owner_id !== ACTOR_ID && record.submitter_id !== ACTOR_ID) {
|
|
expect(prisma.workflowInstance.findFirst).toHaveBeenCalledWith({
|
|
where: { entity_type: "reimbursement", entity_id: REIMBURSEMENT_ID },
|
|
select: { id: true },
|
|
});
|
|
} else {
|
|
expect(prisma.workflowInstance.findFirst).not.toHaveBeenCalled();
|
|
}
|
|
});
|
|
});
|