test(api): cover assistant timeline project shifts

This commit is contained in:
2026-04-01 00:35:28 +02:00
parent 7949aeb2e4
commit e76b4b2cfe
@@ -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.",
});
});
});