import { PermissionKey, SystemRole } from "@capakraken/shared"; import { describe, expect, it, vi } from "vitest"; import { importExportRouter } from "../router/import-export.js"; import { createCallerFactory } from "../trpc.js"; const createCaller = createCallerFactory(importExportRouter); function createProtectedCaller( db: Record, options: { role?: SystemRole; granted?: PermissionKey[]; denied?: PermissionKey[]; } = {}, ) { const { role = SystemRole.USER, granted = [], denied = [] } = options; const hasOverrides = granted.length > 0 || denied.length > 0; 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: hasOverrides ? { ...(granted.length > 0 ? { granted } : {}), ...(denied.length > 0 ? { denied } : {}) } : null, }, roleDefaults: null, }); } describe("import-export router", () => { it("exports resources for controller callers", async () => { const caller = createProtectedCaller( { resource: { findMany: vi.fn().mockResolvedValue([ { eid: "E-001", displayName: "Ada Lovelace", email: "ada@example.com", chapter: "Consulting", lcrCents: 10000, ucrCents: 20000, currency: "EUR", chargeabilityTarget: 0.8, dynamicFields: {}, }, ]), }, blueprint: { findMany: vi.fn().mockResolvedValue([]), }, }, { role: SystemRole.CONTROLLER }, ); const csv = await caller.exportResourcesCSV(); expect(csv).toContain("eid,displayName,email,chapter"); expect(csv).toContain("E-001,Ada Lovelace"); }); it("allows managers with import permission to import CSV rows", async () => { const resourceFindFirst = vi.fn().mockResolvedValue({ id: "res_1", displayName: "Ada", email: "ada-old@example.com", chapter: "Old", lcrCents: 9000, }); const resourceUpdate = vi.fn().mockResolvedValue({ id: "res_1" }); const auditCreate = vi.fn().mockResolvedValue({ id: "audit_1" }); const importDb: Record = { resource: { findFirst: resourceFindFirst, update: resourceUpdate, }, auditLog: { create: auditCreate, }, }; importDb["$transaction"] = vi.fn(async (fn: (tx: unknown) => unknown) => fn(importDb)); const caller = createProtectedCaller( importDb, { role: SystemRole.MANAGER, granted: [PermissionKey.IMPORT_DATA], }, ); const result = await caller.importCSV({ entityType: "resources", rows: [{ eid: "E-001", displayName: "Ada Lovelace" }], dryRun: false, }); expect(resourceUpdate).toHaveBeenCalledWith({ where: { id: "res_1" }, data: { displayName: "Ada Lovelace", email: "ada-old@example.com", chapter: "Old", lcrCents: 9000, }, }); expect(result.updated).toBe(1); }); it("blocks managers without the import permission", async () => { const caller = createProtectedCaller( { resource: { findFirst: vi.fn(), update: vi.fn(), }, auditLog: { create: vi.fn(), }, }, { role: SystemRole.MANAGER, denied: [PermissionKey.IMPORT_DATA], }, ); await expect( caller.importCSV({ entityType: "resources", rows: [], dryRun: true, }), ).rejects.toThrow(PermissionKey.IMPORT_DATA); }); });