import { beforeEach, describe, expect, it, vi } from "vitest"; import { PermissionKey, SystemRole } from "@capakraken/shared"; vi.mock("@capakraken/application", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, countPlanningEntries: vi.fn().mockResolvedValue({ countsByRoleId: new Map() }), getDashboardBudgetForecast: vi.fn().mockResolvedValue([]), getDashboardPeakTimes: vi.fn().mockResolvedValue([]), listAssignmentBookings: vi.fn().mockResolvedValue([]), }; }); import { countPlanningEntries } from "@capakraken/application"; import { executeTool } from "../router/assistant-tools.js"; import { createToolContext } from "./assistant-tools-master-data-read-test-helpers.js"; describe("assistant master data blueprint and rate-card read tools", () => { beforeEach(() => { vi.clearAllMocks(); vi.mocked(countPlanningEntries).mockResolvedValue({ countsByRoleId: new Map() }); }); it("routes blueprint and rate card reads through their backing routers", async () => { const db = { blueprint: { findMany: vi.fn().mockResolvedValue([ { id: "bp_project", name: "Project Default", _count: { projects: 3 }, }, ]), findUnique: vi.fn().mockResolvedValue({ id: "bp_project", name: "Project Default", fieldDefs: [{ key: "market", type: "text" }], rolePresets: [{ role: "Consulting", share: 0.5 }], }), }, rateCard: { findMany: vi.fn().mockResolvedValue([ { id: "rc_2026", name: "Standard 2026", effectiveFrom: new Date("2026-01-01T00:00:00.000Z"), effectiveTo: null, _count: { lines: 12 }, client: null, }, ]), }, }; const ctx = createToolContext(db, { userRole: SystemRole.ADMIN, permissions: [PermissionKey.VIEW_PLANNING, PermissionKey.VIEW_COSTS], }); const blueprintsResult = await executeTool("list_blueprints", "{}", ctx); const blueprintResult = await executeTool( "get_blueprint", JSON.stringify({ identifier: "bp_project" }), ctx, ); const rateCardsResult = await executeTool( "list_rate_cards", JSON.stringify({ query: "Standard", limit: 10 }), ctx, ); expect(db.blueprint.findMany).toHaveBeenCalledWith({ select: { id: true, name: true, _count: { select: { projects: true } }, }, orderBy: { name: "asc" }, }); expect(db.blueprint.findUnique).toHaveBeenCalledWith({ where: { id: "bp_project" }, }); expect(db.rateCard.findMany).toHaveBeenCalledWith({ where: { isActive: true, name: { contains: "Standard", mode: "insensitive" }, }, include: { _count: { select: { lines: true } }, client: { select: { id: true, name: true, code: true } }, }, orderBy: [{ isActive: "desc" }, { effectiveFrom: "desc" }, { name: "asc" }], }); expect(JSON.parse(blueprintsResult.content)).toEqual([ { id: "bp_project", name: "Project Default", projectCount: 3, }, ]); expect(JSON.parse(blueprintResult.content)).toEqual( expect.objectContaining({ id: "bp_project", name: "Project Default", fieldDefs: [{ key: "market", type: "text" }], rolePresets: [{ role: "Consulting", share: 0.5 }], }), ); expect(JSON.parse(rateCardsResult.content)).toEqual([ { id: "rc_2026", name: "Standard 2026", effectiveFrom: "2026-01-01", effectiveTo: null, lineCount: 12, }, ]); }); it("returns a stable assistant error when a blueprint cannot be resolved for read access", async () => { const ctx = createToolContext( { blueprint: { findUnique: vi.fn().mockResolvedValue(null), findFirst: vi.fn().mockResolvedValue(null), }, }, { userRole: SystemRole.ADMIN, permissions: [PermissionKey.VIEW_PLANNING], }, ); const result = await executeTool( "get_blueprint", JSON.stringify({ identifier: "Missing Blueprint" }), ctx, ); expect(JSON.parse(result.content)).toEqual({ error: "Blueprint not found: Missing Blueprint", }); }); });