Files
omniai-ds-code-package/src/utils/translateTaskError.test.ts
T

82 lines
4.1 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { classifyTaskError, translateTaskError, type TaskErrorCategory } from "./translateTaskError";
// 每条规则至少一个正例,按规则顺序排列(classifyTaskError 先匹配先返回)。
const RULE_CASES: Array<{ name: string; input: string; category: TaskErrorCategory }> = [
{ name: "content policy", input: "content violated our policies", category: "content_policy" },
{ name: "nsfw", input: "image flagged as nsfw", category: "content_policy" },
{ name: "auth 401", input: "401 Unauthorized", category: "auth_failure" },
{ name: "token expired", input: "token expired", category: "auth_failure" },
{ name: "insufficient balance 402", input: "402 Payment Required", category: "insufficient_balance" },
{ name: "余额不足", input: "余额不足", category: "insufficient_balance" },
{ name: "concurrency pool full", input: "concurrency pool is full", category: "concurrency_busy" },
{ name: "rate limit 429", input: "429 Too Many Requests", category: "concurrency_busy" },
{ name: "unsupported model", input: "model not found", category: "unsupported_model" },
{ name: "invalid asset", input: "invalid image format", category: "invalid_asset" },
{ name: "network ECONNREFUSED", input: "fetch failed: ECONNREFUSED", category: "network_failure" },
{ name: "timeout ETIMEDOUT", input: "ETIMEDOUT", category: "timeout" },
{ name: "quota exceeded", input: "quota exceeded", category: "insufficient_balance" },
{ name: "cancelled", input: "task was cancelled", category: "cancelled" },
{ name: "已取消", input: "任务已取消", category: "cancelled" },
{ name: "all providers failed", input: "all providers failed", category: "concurrency_busy" },
{ name: "500 server error", input: "500 Internal Server Error", category: "network_failure" },
{ name: "forbidden 403", input: "403 Forbidden", category: "auth_failure" },
{ name: "aborted", input: "request aborted", category: "timeout" },
];
describe("classifyTaskError rule coverage", () => {
for (const { name, input, category } of RULE_CASES) {
it(`classifies "${name}" as ${category}`, () => {
const result = classifyTaskError(input);
expect(result.category).toBe(category);
expect(result.message).toBeTruthy();
expect(result.action).toBeTruthy();
});
}
});
describe("classifyTaskError edge cases", () => {
it("returns unknown for empty/null/undefined", () => {
expect(classifyTaskError("").category).toBe("unknown");
expect(classifyTaskError(undefined).category).toBe("unknown");
expect(classifyTaskError(null).category).toBe("unknown");
});
it("returns the raw (truncated) message for unrecognized Chinese errors", () => {
const result = classifyTaskError("这是一条未知的中文错误信息");
expect(result.category).toBe("unknown");
expect(result.message).toContain("未知");
expect(result.message).not.toContain("服务异常");
});
it("truncates long Chinese errors to 80 chars + ellipsis", () => {
const long = "错误".repeat(50);
const result = classifyTaskError(long);
expect(result.message.endsWith("...")).toBe(true);
expect(result.message.length).toBeLessThanOrEqual(83);
});
it("returns generic service message for unrecognized English errors", () => {
const result = classifyTaskError("something completely unexpected");
expect(result.category).toBe("unknown");
expect(result.message).toBe("服务异常,请稍后重试");
});
});
describe("classifyTaskError rule ordering (first match wins)", () => {
it("content_policy beats auth_failure when both patterns present", () => {
// "nsfw" appears before "401" in rule order
const result = classifyTaskError("nsfw content with 401");
expect(result.category).toBe("content_policy");
});
});
describe("translateTaskError", () => {
it("returns the message from classifyTaskError", () => {
expect(translateTaskError("401")).toBe("登录已过期,请重新登录");
});
it("returns generic message for empty input", () => {
expect(translateTaskError("")).toBe("任务失败,请重试");
});
});