Files
CapaKraken/packages/api/src/__tests__/assistant-tools-planning-rate-read.test.ts
T

148 lines
4.3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { PermissionKey, SystemRole } from "@capakraken/shared";
vi.mock("@capakraken/application", async (importOriginal) => {
const actual = await importOriginal<typeof import("@capakraken/application")>();
return {
...actual,
approveEstimateVersion: vi.fn(),
cloneEstimate: vi.fn(),
commitDispoImportBatch: vi.fn(),
countPlanningEntries: vi.fn().mockResolvedValue({ countsByRoleId: new Map() }),
createEstimateExport: vi.fn(),
createEstimatePlanningHandoff: vi.fn(),
createEstimateRevision: vi.fn(),
assessDispoImportReadiness: vi.fn(),
loadResourceDailyAvailabilityContexts: vi.fn().mockResolvedValue(new Map()),
getDashboardDemand: vi.fn().mockResolvedValue([]),
getDashboardBudgetForecast: vi.fn().mockResolvedValue([]),
getDashboardOverview: vi.fn(),
getDashboardSkillGapSummary: vi.fn().mockResolvedValue({
roleGaps: [],
totalOpenPositions: 0,
skillSupplyTop10: [],
resourcesByRole: [],
}),
getDashboardProjectHealth: vi.fn().mockResolvedValue([]),
getDashboardPeakTimes: vi.fn().mockResolvedValue([]),
getDashboardTopValueResources: vi.fn().mockResolvedValue([]),
getEstimateById: vi.fn(),
listAssignmentBookings: vi.fn().mockResolvedValue([]),
stageDispoImportBatch: vi.fn(),
submitEstimateVersion: vi.fn(),
updateEstimateDraft: vi.fn(),
};
});
import { executeTool } from "../router/assistant-tools.js";
import { createToolContext } from "./assistant-tools-planning-read-test-helpers.js";
describe("assistant planning rate read tools", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("routes rate resolution through the rate-card router path", async () => {
const db = {
resource: {
findUnique: vi.fn().mockResolvedValue({
id: "res_1",
eid: "EMP-001",
displayName: "Bruce Banner",
chapter: "Delivery",
lcrCents: 8_000,
areaRole: { name: "Pipeline TD" },
managementLevel: { id: "ml_senior" },
}),
findFirst: vi.fn(),
},
role: {
findFirst: vi.fn().mockResolvedValue({ id: "role_1" }),
},
rateCard: {
findMany: vi.fn().mockResolvedValue([
{
id: "rc_2026",
name: "Standard 2026",
client: null,
lines: [
{
id: "line_1",
chapter: "Delivery",
seniority: "Senior",
costRateCents: 12_000,
billRateCents: 18_000,
role: { id: "role_1", name: "Pipeline TD" },
managementLevelId: "ml_senior",
},
],
},
]),
findUnique: vi.fn(),
},
};
const ctx = createToolContext(db, {
userRole: SystemRole.CONTROLLER,
permissions: [PermissionKey.VIEW_COSTS],
});
const result = await executeTool(
"resolve_rate",
JSON.stringify({ resourceId: "res_1" }),
ctx,
);
expect(db.resource.findUnique).toHaveBeenNthCalledWith(1, {
where: { id: "res_1" },
select: {
id: true,
eid: true,
displayName: true,
chapter: true,
isActive: true,
},
});
expect(db.resource.findUnique).toHaveBeenNthCalledWith(2, {
where: { id: "res_1" },
select: {
id: true,
displayName: true,
chapter: true,
areaRole: { select: { name: true } },
},
});
expect(JSON.parse(result.content)).toEqual({
rateCard: "Standard 2026",
resource: "Bruce Banner",
rate: "120,00 EUR",
rateCents: 12000,
matchedBy: "role: Pipeline TD",
});
});
it("returns a stable assistant error when rate resolution receives an invalid date", async () => {
const ctx = createToolContext(
{
rateCard: {
findMany: vi.fn(),
findUnique: vi.fn(),
},
},
{
userRole: SystemRole.CONTROLLER,
permissions: [PermissionKey.VIEW_COSTS],
},
);
const result = await executeTool(
"resolve_rate",
JSON.stringify({ roleName: "Pipeline TD", date: "2026-99-01" }),
ctx,
);
expect(JSON.parse(result.content)).toEqual({
error: "Invalid date: 2026-99-01",
});
});
});