fix(api): harden broadcast and assistant fallback errors

This commit is contained in:
2026-03-30 12:03:27 +02:00
parent 22cff9648e
commit 6a6e98b5f7
5 changed files with 305 additions and 57 deletions
@@ -2170,14 +2170,15 @@ describe("assistant import/export and dispo tools", () => {
});
it("returns a stable assistant error when a broadcast target resolves to no recipients", async () => {
const create = vi.fn().mockResolvedValue({
id: "broadcast_empty",
title: "Office update",
targetType: "user",
});
const ctx = createToolContext(
{
notificationBroadcast: {
create: vi.fn().mockResolvedValue({
id: "broadcast_empty",
title: "Office update",
targetType: "user",
}),
create,
},
},
{ userRole: SystemRole.MANAGER },
@@ -2195,6 +2196,39 @@ describe("assistant import/export and dispo tools", () => {
expect(JSON.parse(result.content)).toEqual({
error: "No recipients matched the broadcast target.",
});
expect(create).not.toHaveBeenCalled();
});
it("returns a stable assistant error when broadcast creation fails because the sender user is missing", async () => {
const ctx = createToolContext(
{
user: {
findMany: vi.fn().mockResolvedValue([{ id: "user_2" }]),
},
notificationBroadcast: {
create: vi.fn().mockRejectedValue(
Object.assign(new Error("Foreign key constraint failed"), {
code: "P2003",
meta: { field_name: "NotificationBroadcast_senderId_fkey" },
}),
),
},
},
{ userRole: SystemRole.MANAGER },
);
const result = await executeTool(
"send_broadcast",
JSON.stringify({
title: "Office update",
targetType: "all",
}),
ctx,
);
expect(JSON.parse(result.content)).toEqual({
error: "Sender user not found with the given criteria.",
});
});
it("reads broadcast details through the real notification router and rejects plain users", async () => {
@@ -2770,6 +2804,58 @@ describe("assistant import/export and dispo tools", () => {
setup: () => vi.mocked(updateEstimateDraft).mockRejectedValueOnce(new Error("Estimate has no working version")),
expected: "Estimate has no working version.",
},
{
name: "update_estimate_draft missing scope item reference",
toolName: "update_estimate_draft",
payload: {
id: "est_scope_missing",
baseCurrency: "EUR",
assumptions: [],
scopeItems: [],
demandLines: [],
resourceSnapshots: [],
metrics: [],
},
permission: PermissionKey.MANAGE_PROJECTS,
db: {
estimate: {
findUnique: vi.fn().mockResolvedValue({ projectId: null }),
},
},
setup: () => vi.mocked(updateEstimateDraft).mockRejectedValueOnce(
Object.assign(new Error("Foreign key constraint failed"), {
code: "P2003",
meta: { field_name: "EstimateScopeItem_scopeItemId_fkey" },
}),
),
expected: "Estimate scope item not found with the given criteria.",
},
{
name: "update_estimate_draft generic missing estimate reference",
toolName: "update_estimate_draft",
payload: {
id: "est_reference_missing",
baseCurrency: "EUR",
assumptions: [],
scopeItems: [],
demandLines: [],
resourceSnapshots: [],
metrics: [],
},
permission: PermissionKey.MANAGE_PROJECTS,
db: {
estimate: {
findUnique: vi.fn().mockResolvedValue({ projectId: null }),
},
},
setup: () => vi.mocked(updateEstimateDraft).mockRejectedValueOnce(
Object.assign(new Error("Foreign key constraint failed"), {
code: "P2003",
meta: { field_name: "EstimateVersion_estimateId_fkey" },
}),
),
expected: "One of the referenced project, role, resource, or scope items no longer exists.",
},
{
name: "submit_estimate_version missing version",
toolName: "submit_estimate_version",