From e76b4b2cfe4630df660da066e700aa6ffd75cd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Wed, 1 Apr 2026 00:35:28 +0200 Subject: [PATCH] test(api): cover assistant timeline project shifts --- ...tant-tools-timeline-project-shifts.test.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 packages/api/src/__tests__/assistant-tools-timeline-project-shifts.test.ts diff --git a/packages/api/src/__tests__/assistant-tools-timeline-project-shifts.test.ts b/packages/api/src/__tests__/assistant-tools-timeline-project-shifts.test.ts new file mode 100644 index 0000000..f3f50eb --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-timeline-project-shifts.test.ts @@ -0,0 +1,131 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { PermissionKey, SystemRole } from "@capakraken/shared"; + +import { createToolContext, executeTool } from "./assistant-tools-timeline-shifts-test-helpers.js"; + +describe("assistant timeline project shift tools", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("applies timeline project shifts through the real timeline router mutation", async () => { + const { listAssignmentBookings } = await import("@capakraken/application"); + vi.mocked(listAssignmentBookings).mockResolvedValueOnce([]); + + const db = { + project: { + findUnique: vi.fn().mockResolvedValue({ + id: "project_1", + name: "Gelddruckmaschine", + shortCode: "GDM", + status: "ACTIVE", + responsiblePerson: null, + budgetCents: 100000, + winProbability: 100, + startDate: new Date("2026-03-16"), + endDate: new Date("2026-03-20"), + }), + update: vi.fn().mockResolvedValue({ + id: "project_1", + startDate: new Date("2026-03-23"), + endDate: new Date("2026-03-27"), + }), + }, + demandRequirement: { + findMany: vi.fn().mockResolvedValue([]), + }, + assignment: { + findMany: vi.fn().mockResolvedValue([]), + }, + auditLog: { + create: vi.fn().mockResolvedValue({}), + }, + $transaction: vi.fn(async (callback: (tx: unknown) => unknown) => callback(db)), + }; + const ctx = createToolContext( + db, + [PermissionKey.MANAGE_ALLOCATIONS, PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS], + SystemRole.MANAGER, + ); + + const result = await executeTool( + "apply_timeline_project_shift", + JSON.stringify({ + projectIdentifier: "project_1", + newStartDate: "2026-03-23", + newEndDate: "2026-03-27", + }), + ctx, + ); + + expect(result.action).toEqual({ type: "invalidate", scope: ["allocation", "timeline", "project"] }); + expect(JSON.parse(result.content)).toEqual( + expect.objectContaining({ + success: true, + project: expect.objectContaining({ + id: "project_1", + startDate: "2026-03-23", + endDate: "2026-03-27", + }), + validation: expect.objectContaining({ + valid: true, + }), + }), + ); + expect(db.project.update).toHaveBeenCalledWith( + expect.objectContaining({ + where: { id: "project_1" }, + }), + ); + }); + + it("returns a stable project-not-found error if the timeline shift target disappears mid-mutation", async () => { + const { listAssignmentBookings } = await import("@capakraken/application"); + vi.mocked(listAssignmentBookings).mockResolvedValueOnce([]); + + const db = { + project: { + findUnique: vi + .fn() + .mockResolvedValueOnce({ + id: "project_1", + name: "Gelddruckmaschine", + shortCode: "GDM", + status: "ACTIVE", + responsiblePerson: null, + budgetCents: 100000, + winProbability: 100, + startDate: new Date("2026-03-16"), + endDate: new Date("2026-03-20"), + }) + .mockResolvedValueOnce(null), + }, + demandRequirement: { + findMany: vi.fn().mockResolvedValue([]), + }, + assignment: { + findMany: vi.fn().mockResolvedValue([]), + }, + }; + const ctx = createToolContext( + db, + [PermissionKey.MANAGE_ALLOCATIONS, PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS], + SystemRole.MANAGER, + ); + + const result = await executeTool( + "apply_timeline_project_shift", + JSON.stringify({ + projectIdentifier: "project_1", + newStartDate: "2026-03-23", + newEndDate: "2026-03-27", + }), + ctx, + ); + + expect(result.action).toBeUndefined(); + expect(JSON.parse(result.content)).toEqual({ + error: "Project not found with the given criteria.", + }); + }); +});