import { describe, expect, it } from "vitest"; import { classifyCcFailure, conflictCheckOperatorMessage, describeCcFailureForOperator, formatCcCause, formatImapSkipReason, formatMailLastError, formatOAuthCallbackError, formatOperatorError, } from "@/constants/error-copy"; describe("formatOperatorError", () => { it("translates last_error machine codes", () => { expect(formatMailLastError("NO_SHIPMENT_ROWS")).toMatch(/未解析到货件/); expect(formatMailLastError("NO_SUPPORTED_SPREADSHEET")).toMatch(/表格附件/); expect(formatMailLastError("NO_BODY_NO_ATTACHMENT")).toMatch(/没有正文/); expect(formatMailLastError("ATTACHMENT_TOO_LARGE")).toMatch(/过大/); expect(formatMailLastError("MIME_PARSE_ERROR")).toMatch(/格式损坏/); expect(formatMailLastError("missing_columns:仓库ID")).toMatch(/缺列/); expect(formatMailLastError("INVALID_CONTAINER_NO:TRHU8524770")).toMatch( /TRHU8524770/, ); }); it("does not show Unauthorized / Invalid body to operators", () => { expect(formatOperatorError("Unauthorized", "UNAUTHORIZED")).toMatch(/登录/); expect(formatOperatorError("Unauthorized")).toMatch(/CarrierCentral|权限/); expect(formatOperatorError("Invalid body")).toMatch(/提交内容|必填/); expect(formatOperatorError("Mail not found")).toMatch(/邮件/); expect(formatMailLastError("Unauthorized")).not.toMatch(/Unauthorized/i); expect(formatMailLastError("Invalid body")).not.toMatch(/Invalid/i); }); it("translates CC transport failures", () => { expect(formatCcCause("CC request timeout")).toMatch(/超时/); expect(formatCcCause("CC request failed")).toMatch(/无法连接/); expect(formatCcCause("CC save failed with code 400")).toMatch( /集装箱数据导入|拒绝|400/, ); expect(formatCcCause("GetContainerList timeout")).toMatch( /集装箱列表|超时/, ); expect(formatMailLastError("CC_WRITE_OFF")).toMatch(/未开启/); expect(formatMailLastError("WO_MOCK_OK")).toMatch(/模拟|未写入/); expect(formatMailLastError("WO_MOCK_OK")).not.toMatch(/操作失败/); expect(formatMailLastError("XFER_MOCK_OK")).toMatch(/模拟|未写入/); expect(formatMailLastError("DO_MOCK_OK")).toMatch(/模拟|未写入/); expect(formatCcCause("Unauthorized")).not.toMatch(/Unauthorized/i); }); it("keeps CC Chinese info even when it embeds FBACode / charset lists", () => { const raw = "第60行的FBACode是空值或者只输入了正常英文字符[_- ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz]以外的字符。"; const out = formatCcCause(raw); expect(out).toMatch(/第60行/); expect(out).toMatch(/目的代码/); expect(out).not.toMatch(/请稍后重试或到 CC 核对/); }); it("keeps already-Chinese messages", () => { expect(formatOperatorError("邮件不存在")).toBe("邮件不存在"); expect(formatOperatorError("柜号必填")).toBe("柜号必填"); }); it("rewrites English embedded in Chinese", () => { expect( formatOperatorError("查柜失败:GetContainerList timeout,默认降级工单"), ).toMatch(/集装箱列表|超时/); }); it("keeps Chinese packing-list errors that mention Excel/xlsx", () => { expect( formatOperatorError( "解析装箱表失败,请确认文件为有效的 Excel(xlsx)", "PARSE_FAILED", ), ).toMatch(/装箱表|Excel|xlsx/); expect( formatOperatorError( "未能从表格解析出货件行,请确认是卡派清单等含「渠道/件数/仓库」表头的 xlsx", "PARSE_FAILED", ), ).toMatch(/货件行|卡派清单/); }); it("maps OAuth and IMAP skip reasons", () => { expect(formatOAuthCallbackError("missing_code")).toMatch(/授权码/); expect(formatImapSkipReason("no_credentials")).toMatch(/邮箱/); expect(formatImapSkipReason("SKIP_BLACKLIST")).toMatch(/黑名单/); }); it("classifies conflict check failures for operators", () => { expect(classifyCcFailure("CC_LOGIN_FAILED:账户或密码错误")).toBe("login"); expect(classifyCcFailure("访问次数限制,请稍后再试")).toBe("rate_limit"); expect(classifyCcFailure("GetContainerList timeout")).toBe("timeout"); expect( conflictCheckOperatorMessage("login", "CC_LOGIN_FAILED:401"), ).toMatch(/账号|密码/); expect(conflictCheckOperatorMessage("rate_limit")).toMatch(/每分钟|60/); }); it("maps CC login credential errors", () => { expect(formatCcCause("CC_CREDENTIALS_MISSING")).toMatch(/未配置/); expect(formatCcCause("CC_LOGIN_FAILED:账户或密码错误")).toMatch(/密码/); }); it("describeCcFailureForOperator exposes kind and message", () => { const login = describeCcFailureForOperator("CC_LOGIN_FAILED:账户或密码错误"); expect(login.kind).toBe("login"); expect(login.kindLabel).toMatch(/登录/); expect(login.message).toMatch(/账号|密码/); const validation = describeCcFailureForOperator( "以下字段未填写,不能保存:柜型", ); expect(validation.kind).toBe("validation"); expect(validation.message).toMatch(/柜型|40HQ/); }); });