import { ImportBatchStatus } from "@capakraken/db"; import { SystemRole } from "@capakraken/shared"; import { beforeEach, describe, expect, it, vi } from "vitest"; const { assessDispoImportReadiness, stageDispoImportBatch, } = vi.hoisted(() => ({ assessDispoImportReadiness: vi.fn(), stageDispoImportBatch: vi.fn(), })); const { createAuditEntry } = vi.hoisted(() => ({ createAuditEntry: vi.fn(), })); vi.mock("@capakraken/application", () => ({ assessDispoImportReadiness, stageDispoImportBatch, })); vi.mock("../lib/audit.js", () => ({ createAuditEntry, })); import { dispoRouter } from "../router/dispo.js"; import { createCallerFactory } from "../trpc.js"; const createCaller = createCallerFactory(dispoRouter); function createDispoCaller( db: Record, options: { role?: SystemRole } = {}, ) { const { role = SystemRole.ADMIN } = options; return createCaller({ session: { user: { email: "user@example.com", name: "User", image: null }, expires: "2099-01-01T00:00:00.000Z", }, db: db as never, dbUser: { id: role === SystemRole.ADMIN ? "user_admin" : "user_1", systemRole: role, permissionOverrides: null, }, }); } describe("dispo router", () => { beforeEach(() => { vi.clearAllMocks(); }); it("requires admin access for dispo import procedures", async () => { const findMany = vi.fn(); const caller = createDispoCaller( { importBatch: { findMany } }, { role: SystemRole.USER }, ); await expect(caller.listImportBatches({ limit: 10 })).rejects.toMatchObject({ code: "FORBIDDEN", message: "Admin role required", }); await expect( caller.stageImportBatch({ chargeabilityWorkbookPath: "/tmp/chargeability.xlsx", planningWorkbookPath: "/tmp/planning.xlsx", referenceWorkbookPath: "/tmp/reference.xlsx", }), ).rejects.toMatchObject({ code: "FORBIDDEN", message: "Admin role required", }); expect(findMany).not.toHaveBeenCalled(); expect(stageDispoImportBatch).not.toHaveBeenCalled(); }); it("lists import batches through the thin router wiring", async () => { const findMany = vi.fn().mockResolvedValue([ { id: "batch_2", createdAt: new Date("2026-03-29T00:00:00.000Z") }, { id: "batch_1", createdAt: new Date("2026-03-28T00:00:00.000Z") }, ]); const caller = createDispoCaller({ importBatch: { findMany }, }); const result = await caller.listImportBatches({ limit: 1, status: ImportBatchStatus.STAGED, }); expect(findMany).toHaveBeenCalledWith({ where: { status: ImportBatchStatus.STAGED }, orderBy: { createdAt: "desc" }, take: 2, }); expect(result).toEqual({ items: [{ id: "batch_2", createdAt: new Date("2026-03-29T00:00:00.000Z") }], nextCursor: "batch_1", }); }); it("stages, validates, and cancels import batches through the admin router", async () => { stageDispoImportBatch.mockResolvedValue({ id: "batch_1", status: ImportBatchStatus.STAGED }); assessDispoImportReadiness.mockResolvedValue({ ready: true, issues: [] }); const findUnique = vi.fn().mockResolvedValue({ id: "batch_1", status: ImportBatchStatus.STAGED, }); const update = vi.fn().mockResolvedValue({ id: "batch_1", status: ImportBatchStatus.CANCELLED, }); const caller = createDispoCaller({ importBatch: { findUnique, update }, }); const staged = await caller.stageImportBatch({ chargeabilityWorkbookPath: "/tmp/chargeability.xlsx", notes: "overnight patch", planningWorkbookPath: "/tmp/planning.xlsx", referenceWorkbookPath: "/tmp/reference.xlsx", }); const validated = await caller.validateImportBatch({ chargeabilityWorkbookPath: "/tmp/chargeability.xlsx", planningWorkbookPath: "/tmp/planning.xlsx", referenceWorkbookPath: "/tmp/reference.xlsx", }); const cancelled = await caller.cancelImportBatch({ id: "batch_1" }); expect(stageDispoImportBatch).toHaveBeenCalledWith( expect.objectContaining({ importBatch: { findUnique, update } }), { chargeabilityWorkbookPath: "/tmp/chargeability.xlsx", notes: "overnight patch", planningWorkbookPath: "/tmp/planning.xlsx", referenceWorkbookPath: "/tmp/reference.xlsx", }, ); expect(assessDispoImportReadiness).toHaveBeenCalledWith({ chargeabilityWorkbookPath: "/tmp/chargeability.xlsx", planningWorkbookPath: "/tmp/planning.xlsx", referenceWorkbookPath: "/tmp/reference.xlsx", }); expect(findUnique).toHaveBeenCalledWith({ where: { id: "batch_1" }, select: { id: true, status: true }, }); expect(update).toHaveBeenCalledWith({ where: { id: "batch_1" }, data: { status: ImportBatchStatus.CANCELLED, }, }); expect(staged).toEqual({ id: "batch_1", status: ImportBatchStatus.STAGED }); expect(validated).toEqual({ ready: true, issues: [] }); expect(cancelled).toEqual({ id: "batch_1", status: ImportBatchStatus.CANCELLED }); expect(createAuditEntry).toHaveBeenCalledWith( expect.objectContaining({ entityType: "ImportBatch", entityId: "batch_1", summary: "Cancelled import batch", userId: "user_admin", }), ); }); });