diff --git a/extensions/qa-lab/src/providers/mock-openai/server.test.ts b/extensions/qa-lab/src/providers/mock-openai/server.test.ts index 570aeeaa642..e10229cc2b3 100644 --- a/extensions/qa-lab/src/providers/mock-openai/server.test.ts +++ b/extensions/qa-lab/src/providers/mock-openai/server.test.ts @@ -4240,7 +4240,7 @@ describe("qa mock openai server", () => { expect(body).not.toContain("HEARTBEAT_OK"); }); - it("rejects malformed Anthropic /v1/messages JSON with an invalid_request_error", async () => { + it("rejects malformed or non-object Anthropic /v1/messages JSON", async () => { const server = await startQaMockOpenAiServer({ host: "127.0.0.1", port: 0, @@ -4249,20 +4249,25 @@ describe("qa mock openai server", () => { await server.stop(); }); - const response = await fetch(`${server.baseUrl}/v1/messages`, { - method: "POST", - headers: { "content-type": "application/json" }, - body: '{"model":"claude-opus-4-8","messages":[', - }); + for (const rawBody of ['{"model":"claude-opus-4-8","messages":[', "null", "[]", '"text"']) { + const response = await fetch(`${server.baseUrl}/v1/messages`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: rawBody, + }); - expect(response.status).toBe(400); - const body = (await response.json()) as { - type: string; - error: { type: string; message: string }; - }; - expect(body.type).toBe("error"); - expect(body.error.type).toBe("invalid_request_error"); - expect(body.error.message).toContain("Malformed JSON body"); + expect(response.status).toBe(400); + const body = (await response.json()) as { + type: string; + error: { type: string; message: string }; + }; + expect(body.type).toBe("error"); + expect(body.error.type).toBe("invalid_request_error"); + expect(body.error.message).toContain("Malformed JSON body"); + } + + const health = await fetch(`${server.baseUrl}/healthz`); + expect(health.status).toBe(200); }); it("rejects malformed OpenAI-compatible JSON without crashing the mock server", async () => { diff --git a/extensions/qa-lab/src/providers/mock-openai/server.ts b/extensions/qa-lab/src/providers/mock-openai/server.ts index d7c142c33bb..0bca5c54835 100644 --- a/extensions/qa-lab/src/providers/mock-openai/server.ts +++ b/extensions/qa-lab/src/providers/mock-openai/server.ts @@ -228,7 +228,7 @@ function readBody(req: IncomingMessage): Promise { }); } -function parseOpenAiJsonBody(raw: string): Record | null { +function parseJsonObjectBody(raw: string): Record | null { try { const parsed = raw ? (JSON.parse(raw) as unknown) : {}; return parsed && typeof parsed === "object" && !Array.isArray(parsed) @@ -3438,7 +3438,7 @@ export async function startQaMockOpenAiServer(params?: { host?: string; port?: n } if (req.method === "POST" && url.pathname === "/v1/images/generations") { const raw = await readBody(req); - const body = parseOpenAiJsonBody(raw); + const body = parseJsonObjectBody(raw); if (!body) { writeOpenAiMalformedJsonError(res, "OpenAI Images"); return; @@ -3466,7 +3466,7 @@ export async function startQaMockOpenAiServer(params?: { host?: string; port?: n } if (req.method === "POST" && url.pathname === "/v1/embeddings") { const raw = await readBody(req); - const body = parseOpenAiJsonBody(raw); + const body = parseJsonObjectBody(raw); if (!body) { writeOpenAiMalformedJsonError(res, "OpenAI Embeddings"); return; @@ -3492,7 +3492,7 @@ export async function startQaMockOpenAiServer(params?: { host?: string; port?: n } if (req.method === "POST" && url.pathname === "/v1/responses") { const raw = await readBody(req); - const body = parseOpenAiJsonBody(raw); + const body = parseJsonObjectBody(raw); if (!body) { writeOpenAiMalformedJsonError(res, "OpenAI Responses"); return; @@ -3534,10 +3534,8 @@ export async function startQaMockOpenAiServer(params?: { host?: string; port?: n } if (req.method === "POST" && url.pathname === "/v1/messages") { const raw = await readBody(req); - let body: AnthropicMessagesRequest; - try { - body = raw ? (JSON.parse(raw) as AnthropicMessagesRequest) : {}; - } catch { + const body = parseJsonObjectBody(raw) as AnthropicMessagesRequest | null; + if (!body) { writeJson(res, 400, { type: "error", error: {