import { describe, expect, it } from "vitest"; import { friendlyError, friendlyFromApiError } from "./messages"; describe("friendlyError", () => { it("maps LLM_UNAVAILABLE to copy + a settings action", () => { const e = friendlyError("LLM_UNAVAILABLE", "fallback exhausted"); expect(e.text).toContain("未连接"); expect(e.actionHref).toBe("/settings/providers"); expect(e.actionLabel).toBe("去设置提供商"); }); it("maps NETWORK to friendly copy without leaking raw message", () => { const e = friendlyError("NETWORK", "TypeError: Failed to fetch"); expect(e.text).toBe("网络中断,请检查连接后重试。"); expect(e.actionHref).toBeUndefined(); }); it("falls back to the raw message for an unknown code", () => { const e = friendlyError("WEIRD_CODE", "something specific happened"); expect(e.text).toBe("something specific happened"); }); it("uses generic copy when code is unknown and no message given", () => { expect(friendlyError(undefined).text).toBe("出错了,请稍后重试。"); expect(friendlyError("WEIRD_CODE", " ").text).toBe("出错了,请稍后重试。"); }); }); describe("friendlyFromApiError", () => { it("surfaces a business error envelope code + action (QA #2/#11)", () => { const e = friendlyFromApiError({ error: { code: "LLM_UNAVAILABLE", message: "x" } }); expect(e.text).toContain("未连接"); expect(e.actionHref).toBe("/settings/providers"); }); it("maps a FastAPI 422 detail envelope to friendly VALIDATION copy (no leak)", () => { const e = friendlyFromApiError({ detail: [{ msg: "Input should be >= 1", loc: ["volume"] }] }); expect(e.text).toBe("提交内容有误,请检查后重试。"); }); it("falls back to generic copy for null/unknown shapes", () => { expect(friendlyFromApiError(null).text).toBe("出错了,请稍后重试。"); expect(friendlyFromApiError({ weird: 1 }).text).toBe("出错了,请稍后重试。"); }); });