Files
CapaKraken/packages/api/src/__tests__/calculation-rule-procedure-support.test.ts
T

193 lines
5.4 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { PROJECT_BRIEF_SELECT } from "../db/selects.js";
import { createAuditEntry } from "../lib/audit.js";
import {
createCalculationRule,
deleteCalculationRule,
getCalculationRuleById,
listActiveCalculationRules,
listCalculationRules,
updateCalculationRule,
} from "../router/calculation-rule-procedure-support.js";
vi.mock("../lib/audit.js", () => ({
createAuditEntry: vi.fn(),
}));
function createContext(db: Record<string, unknown>) {
return {
db: db as never,
dbUser: { id: "user_mgr" },
};
}
describe("calculation-rule-procedure-support", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("lists calculation rules with the expected project include", async () => {
const findMany = vi.fn().mockResolvedValue([{ id: "calc_1" }]);
const ctx = createContext({
calculationRule: { findMany },
});
const result = await listCalculationRules(ctx);
expect(result).toEqual([{ id: "calc_1" }]);
expect(findMany).toHaveBeenCalledWith({
orderBy: [{ priority: "desc" }, { name: "asc" }],
include: { project: { select: PROJECT_BRIEF_SELECT } },
});
});
it("gets a rule by id with the expected project include", async () => {
const findUnique = vi.fn().mockResolvedValue({ id: "calc_1", name: "Rush Fee" });
const ctx = createContext({
calculationRule: { findUnique },
});
const result = await getCalculationRuleById(ctx, { id: "calc_1" });
expect(result).toEqual({ id: "calc_1", name: "Rush Fee" });
expect(findUnique).toHaveBeenCalledWith({
where: { id: "calc_1" },
include: { project: { select: PROJECT_BRIEF_SELECT } },
});
});
it("lists only active rules for engine use", async () => {
const findMany = vi.fn().mockResolvedValue([{ id: "calc_2", isActive: true }]);
const ctx = createContext({
calculationRule: { findMany },
});
const result = await listActiveCalculationRules(ctx);
expect(result).toEqual([{ id: "calc_2", isActive: true }]);
expect(findMany).toHaveBeenCalledWith({
where: { isActive: true },
orderBy: [{ priority: "desc" }],
});
});
it("creates a rule and records an audit entry", async () => {
const created = {
id: "calc_3",
name: "Vacation Discount",
triggerType: "VACATION",
costEffect: "REDUCE",
chargeabilityEffect: "COUNT",
priority: 10,
isActive: true,
};
const create = vi.fn().mockResolvedValue(created);
const ctx = createContext({
calculationRule: { create },
});
const result = await createCalculationRule(ctx, {
name: "Vacation Discount",
triggerType: "VACATION",
costEffect: "REDUCE",
chargeabilityEffect: "COUNT",
priority: 10,
isActive: true,
});
expect(result).toBe(created);
expect(create).toHaveBeenCalledWith({
data: {
name: "Vacation Discount",
triggerType: "VACATION",
costEffect: "REDUCE",
chargeabilityEffect: "COUNT",
priority: 10,
isActive: true,
},
});
expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({
db: ctx.db,
entityType: "CalculationRule",
entityId: "calc_3",
entityName: "Vacation Discount",
action: "CREATE",
userId: "user_mgr",
after: created,
source: "ui",
}));
});
it("updates a rule and records before/after audit snapshots", async () => {
const before = {
id: "calc_4",
name: "Rush Fee",
priority: 90,
isActive: true,
};
const after = {
id: "calc_4",
name: "Rush Fee",
priority: 95,
isActive: false,
};
const findUnique = vi.fn().mockResolvedValue(before);
const update = vi.fn().mockResolvedValue(after);
const ctx = createContext({
calculationRule: { findUnique, update },
});
const result = await updateCalculationRule(ctx, {
id: "calc_4",
priority: 95,
isActive: false,
});
expect(result).toBe(after);
expect(findUnique).toHaveBeenCalledWith({ where: { id: "calc_4" } });
expect(update).toHaveBeenCalledWith({
where: { id: "calc_4" },
data: {
priority: 95,
isActive: false,
},
});
expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({
db: ctx.db,
entityType: "CalculationRule",
entityId: "calc_4",
entityName: "Rush Fee",
action: "UPDATE",
userId: "user_mgr",
before,
after,
source: "ui",
}));
});
it("deletes a rule and records a delete audit entry", async () => {
const rule = { id: "calc_5", name: "Legacy Rule" };
const findUnique = vi.fn().mockResolvedValue(rule);
const deleteFn = vi.fn().mockResolvedValue(rule);
const ctx = createContext({
calculationRule: { findUnique, delete: deleteFn },
});
const result = await deleteCalculationRule(ctx, { id: "calc_5" });
expect(result).toEqual({ success: true });
expect(findUnique).toHaveBeenCalledWith({ where: { id: "calc_5" } });
expect(deleteFn).toHaveBeenCalledWith({ where: { id: "calc_5" } });
expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({
db: ctx.db,
entityType: "CalculationRule",
entityId: "calc_5",
entityName: "Legacy Rule",
action: "DELETE",
userId: "user_mgr",
before: rule,
source: "ui",
}));
});
});