146 lines
4.1 KiB
JavaScript
146 lines
4.1 KiB
JavaScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mockStartCase = vi.fn();
|
|
|
|
vi.mock("@/lib/graph/orchestrator.js", () => ({
|
|
startCase: (...args) => mockStartCase(...args),
|
|
}));
|
|
|
|
describe("app/api/cases/start route", () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("delegates request body to the orchestrator", async () => {
|
|
mockStartCase.mockResolvedValue({
|
|
success: true,
|
|
situationGraph: { nodes: [{ id: "n1" }], edges: [] },
|
|
selectedQuestion: null,
|
|
diagnostics: {},
|
|
});
|
|
|
|
const { POST } = await import("@/app/api/cases/start/route.js");
|
|
const request = new Request("http://localhost/api/cases/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({ scenario: "Scenario text" }),
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
|
|
await POST(request);
|
|
|
|
expect(mockStartCase).toHaveBeenCalledWith({ scenario: "Scenario text" });
|
|
});
|
|
|
|
it("returns 200 on success", async () => {
|
|
const reconstruction = {
|
|
summary: "Validated reconstruction summary",
|
|
relationships: [
|
|
{
|
|
id: "r1",
|
|
fromId: "u-intervention",
|
|
toId: "u-problem",
|
|
relationship: "depends_on",
|
|
description: "The intervention depends on the unresolved problem.",
|
|
confidence: "high",
|
|
},
|
|
],
|
|
};
|
|
mockStartCase.mockResolvedValue({
|
|
success: true,
|
|
reconstruction,
|
|
situationGraph: {
|
|
nodes: [{ id: "n1" }],
|
|
edges: [
|
|
{
|
|
id: "e-unrelated",
|
|
fromNodeId: "n1",
|
|
toNodeId: "n1",
|
|
relationship: "supports",
|
|
},
|
|
],
|
|
},
|
|
selectedQuestion: null,
|
|
diagnostics: {},
|
|
});
|
|
|
|
const { POST } = await import("@/app/api/cases/start/route.js");
|
|
const response = await POST(
|
|
new Request("http://localhost/api/cases/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({ scenario: "Scenario text" }),
|
|
headers: { "content-type": "application/json" },
|
|
}),
|
|
);
|
|
|
|
expect(response.status).toBe(200);
|
|
await expect(response.json()).resolves.toMatchObject({
|
|
success: true,
|
|
reconstruction,
|
|
});
|
|
});
|
|
|
|
it("returns 400 for invalid request input", async () => {
|
|
mockStartCase.mockResolvedValue({
|
|
success: false,
|
|
error: "Invalid start-case request",
|
|
validationErrors: [{ message: "Required" }],
|
|
statusCode: 400,
|
|
});
|
|
|
|
const { POST } = await import("@/app/api/cases/start/route.js");
|
|
const response = await POST(
|
|
new Request("http://localhost/api/cases/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({}),
|
|
headers: { "content-type": "application/json" },
|
|
}),
|
|
);
|
|
|
|
expect(response.status).toBe(400);
|
|
await expect(response.json()).resolves.toMatchObject({
|
|
success: false,
|
|
error: "Invalid start-case request",
|
|
});
|
|
});
|
|
|
|
it("returns provider/internal failures as 5xx without stack traces", async () => {
|
|
mockStartCase.mockResolvedValue({
|
|
success: false,
|
|
error: "Provider unavailable",
|
|
diagnostics: { modelName: "llama3" },
|
|
statusCode: 502,
|
|
rawResponse: '{"reconstruction":{"summary":""}}',
|
|
});
|
|
|
|
const { POST } = await import("@/app/api/cases/start/route.js");
|
|
const response = await POST(
|
|
new Request("http://localhost/api/cases/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({ scenario: "Scenario text" }),
|
|
headers: { "content-type": "application/json" },
|
|
}),
|
|
);
|
|
|
|
expect(response.status).toBe(502);
|
|
const body = await response.json();
|
|
expect(body).toHaveProperty("rawResponse");
|
|
expect(body.rawResponse).toBe('{"reconstruction":{"summary":""}}');
|
|
});
|
|
|
|
it("returns structured 500 on malformed JSON", async () => {
|
|
const { POST } = await import("@/app/api/cases/start/route.js");
|
|
const request = {
|
|
json: vi.fn().mockRejectedValue(new Error("Unexpected token")),
|
|
};
|
|
|
|
const response = await POST(request);
|
|
|
|
expect(response.status).toBe(500);
|
|
await expect(response.json()).resolves.toMatchObject({
|
|
success: false,
|
|
error: "Internal server error",
|
|
});
|
|
});
|
|
});
|