import { expect, test } from "@playwright/test"; import { findImageGenerationFailure } from "@/lib/canvas/image-generation-status"; import { getRequestFailureDetails } from "@/lib/request-error"; import { serverLoader } from "../helpers/canvas-download-server-loader"; test("a terminal image error reaches the stream and persists for disconnected clients", async () => { const chunks: any[] = []; const saved: any[] = []; const load = serverLoader({ "@/lib/db/queries": { saveMessages: async ({ messages }: any) => saved.push(...messages) } }); const { reportImageGenerationFailure } = load("app/(chat)/api/chat/_lib/image-generation-failure.ts"); await reportImageGenerationFailure({ writer: { write: (chunk: any) => chunks.push(chunk) }, chatId: "chat", userMessageId: "original-user", messageId: "request-id", error: new Error("get image url failed"), label: "test", }); const streamed = JSON.parse(chunks.find(chunk => chunk.type === "data-imageGenerationStatus").data); const persisted = findImageGenerationFailure(saved, "original-user"); expect(persisted).toEqual(streamed); expect(persisted).toMatchObject({ phase: "failed", requestId: "request-id", failure: { code: "SOURCE_IMAGE_UNAVAILABLE", outcome: "failed" } }); const text = saved[0].parts[0].text; expect(text).toContain("重新上传原图"); expect(text).toContain("请求编号:request-id"); expect(JSON.parse(chunks.at(-1).data).parts[0].text).toContain("IMAGE_GENERATION_END"); await reportImageGenerationFailure({ writer: { write: () => { throw new Error("browser disconnected"); } }, chatId: "chat", userMessageId: "next-user", messageId: "next-request", error: new Error("get image url failed"), label: "test", }); expect(findImageGenerationFailure(saved, "next-user")?.requestId).toBe("next-request"); }); test("late failures remain associated with their original user request", () => { const status = { phase: "failed" as const, userMessageId: "first", failure: getRequestFailureDetails(new Error("HTTP 524")) }; const messages = [{ role: "user", parts: [] }, { role: "assistant", parts: [{ type: "data-imageGenerationStatus", data: status }] }]; expect(findImageGenerationFailure(messages, "first")).toEqual(status); expect(findImageGenerationFailure(messages, "second")).toBeNull(); expect(findImageGenerationFailure([{ role: "assistant", parts: [{ type: "text", text: "请分析失败原因" }] }], "second")).toBeNull(); });