From a154cd86586b33216c3ee1b2d173c705a65cb23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Wed, 1 Apr 2026 00:27:29 +0200 Subject: [PATCH] test(api): cover assistant org unit mutations --- ...nt-tools-org-unit-mutations-errors.test.ts | 95 +++++++++++ ...t-tools-org-unit-mutations-success.test.ts | 159 ++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 packages/api/src/__tests__/assistant-tools-org-unit-mutations-errors.test.ts create mode 100644 packages/api/src/__tests__/assistant-tools-org-unit-mutations-success.test.ts diff --git a/packages/api/src/__tests__/assistant-tools-org-unit-mutations-errors.test.ts b/packages/api/src/__tests__/assistant-tools-org-unit-mutations-errors.test.ts new file mode 100644 index 0000000..2e163d2 --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-org-unit-mutations-errors.test.ts @@ -0,0 +1,95 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { 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-mutation-test-helpers.js"; + +describe("assistant org unit mutation tools - errors", () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(countPlanningEntries).mockResolvedValue({ countsByRoleId: new Map() }); + }); + + it("returns a stable error when creating an org unit with a missing parent", async () => { + const ctx = createToolContext( + { + orgUnit: { + findUnique: vi.fn().mockResolvedValue(null), + }, + }, + { userRole: SystemRole.ADMIN }, + ); + + const result = await executeTool( + "create_org_unit", + JSON.stringify({ name: "Delivery", level: 6, parentId: "ou_missing" }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual(expect.objectContaining({ + error: "Parent org unit not found with the given criteria.", + })); + }); + + it("returns a stable error when creating an org unit with an invalid child level", async () => { + const ctx = createToolContext( + { + orgUnit: { + findUnique: vi.fn().mockResolvedValue({ + id: "ou_parent", + name: "Delivery", + shortName: "DEL", + level: 6, + parentId: null, + sortOrder: 1, + isActive: true, + }), + }, + }, + { userRole: SystemRole.ADMIN }, + ); + + const result = await executeTool( + "create_org_unit", + JSON.stringify({ name: "Delivery Germany", level: 5, parentId: "ou_parent" }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual(expect.objectContaining({ + error: "Org unit level must be greater than the parent org unit level.", + })); + }); + + it("returns a stable error when updating a missing org unit", async () => { + const ctx = createToolContext( + { + orgUnit: { + findUnique: vi.fn().mockResolvedValue(null), + }, + }, + { userRole: SystemRole.ADMIN }, + ); + + const result = await executeTool( + "update_org_unit", + JSON.stringify({ id: "ou_missing", name: "Delivery Europe" }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual(expect.objectContaining({ + error: "Org unit not found with the given criteria.", + })); + }); +}); diff --git a/packages/api/src/__tests__/assistant-tools-org-unit-mutations-success.test.ts b/packages/api/src/__tests__/assistant-tools-org-unit-mutations-success.test.ts new file mode 100644 index 0000000..b1c1c2d --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-org-unit-mutations-success.test.ts @@ -0,0 +1,159 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { 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-mutation-test-helpers.js"; + +describe("assistant org unit mutation tools - success", () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(countPlanningEntries).mockResolvedValue({ countsByRoleId: new Map() }); + }); + + it("routes org unit mutations through their backing router", async () => { + const db = { + orgUnit: { + findUnique: vi.fn().mockImplementation(async (args?: { where?: { id?: string } }) => { + if (args?.where?.id === "ou_1") { + return { + id: "ou_1", + name: "Operations", + shortName: "OPS", + level: 5, + parentId: null, + sortOrder: 1, + isActive: true, + }; + } + return null; + }), + create: vi.fn().mockResolvedValue({ + id: "ou_1", + name: "Operations", + shortName: "OPS", + level: 5, + parentId: null, + sortOrder: 1, + isActive: true, + }), + update: vi.fn().mockResolvedValue({ + id: "ou_1", + name: "Operations EU", + shortName: null, + level: 5, + parentId: null, + sortOrder: 4, + isActive: false, + }), + }, + auditLog: { + create: vi.fn().mockResolvedValue({ id: "audit_1" }), + }, + }; + const ctx = createToolContext(db, { userRole: SystemRole.ADMIN }); + + const createOrgUnitResult = await executeTool( + "create_org_unit", + JSON.stringify({ name: "Operations", shortName: "OPS", level: 5, sortOrder: 1 }), + ctx, + ); + const updateOrgUnitResult = await executeTool( + "update_org_unit", + JSON.stringify({ id: "ou_1", name: "Operations EU", shortName: null, sortOrder: 4, isActive: false }), + ctx, + ); + + expect(JSON.parse(createOrgUnitResult.content)).toEqual(expect.objectContaining({ + success: true, + orgUnitId: "ou_1", + message: "Created org unit: Operations", + })); + expect(JSON.parse(updateOrgUnitResult.content)).toEqual(expect.objectContaining({ + success: true, + orgUnitId: "ou_1", + message: "Updated org unit: Operations EU", + })); + + expect(db.orgUnit.create).toHaveBeenCalled(); + expect(db.orgUnit.update).toHaveBeenCalled(); + expect(db.auditLog.create).toHaveBeenCalled(); + }); + + it("returns the expected assistant payloads for org unit mutations", async () => { + const db = { + orgUnit: { + findUnique: vi.fn(async ({ + where, + }: { + where: { id: string }; + }) => ( + where.id === "ou_1" + ? { + id: "ou_1", + name: "Delivery", + shortName: "DEL", + level: 5, + parentId: null, + sortOrder: 1, + isActive: true, + } + : null + )), + create: vi.fn().mockResolvedValue({ + id: "ou_1", + name: "Delivery", + shortName: "DEL", + level: 5, + parentId: null, + sortOrder: 1, + isActive: true, + }), + update: vi.fn().mockResolvedValue({ + id: "ou_1", + name: "Delivery Europe", + shortName: "DEU", + level: 5, + parentId: null, + sortOrder: 2, + isActive: true, + }), + }, + auditLog: { + create: vi.fn().mockResolvedValue({ id: "audit_1" }), + }, + }; + const ctx = createToolContext(db, { userRole: SystemRole.ADMIN }); + + const createOrgUnitResult = await executeTool( + "create_org_unit", + JSON.stringify({ name: "Delivery", shortName: "DEL", level: 5, sortOrder: 1 }), + ctx, + ); + const updateOrgUnitResult = await executeTool( + "update_org_unit", + JSON.stringify({ id: "ou_1", name: "Delivery Europe", shortName: "DEU", sortOrder: 2 }), + ctx, + ); + + expect(JSON.parse(createOrgUnitResult.content)).toEqual(expect.objectContaining({ + success: true, + message: "Created org unit: Delivery", + })); + expect(JSON.parse(updateOrgUnitResult.content)).toEqual(expect.objectContaining({ + success: true, + message: "Updated org unit: Delivery Europe", + })); + }); +});