import { describe, expect, it } from "vitest"; import { RpaError } from "@/modules/rpa/errors"; import { RpaDataInvalidError } from "@/modules/quote/types"; import { formatQuoteErrorMessage, isChineseUserFacingMessage, resolveQuoteFailureCode, resolveQuoteFailureMessage, toChineseUserFacingMessage, translateKnownEnglishPhrases, } from "@/modules/quote/quote-error-messages"; describe("quote-error-messages", () => { it("RpaError 保留细分 error_code", () => { expect( resolveQuoteFailureCode( new RpaError("ADDRESS_SUGGESTION_NOT_FOUND", "未找到地址"), ), ).toBe("ADDRESS_SUGGESTION_NOT_FOUND"); }); it("技术英文原文不直出,回退中文默认", () => { const msg = resolveQuoteFailureMessage( new RpaError( "STRUCT_CHANGE", "locator.waitFor: Timeout 15000ms exceeded", ), "QUOTE_ENTRY_UNAVAILABLE", ); expect(msg).toMatch(/自动化操作超时|报价入口/); expect(msg).not.toMatch(/locator\.waitFor/i); }); it("Playwright 超时译为具体中文原因,不再吞成通用「暂时无法获取」", () => { const msg = toChineseUserFacingMessage( "locator.waitFor: Timeout 30000ms exceeded.\nCall log:\n - waiting for getByTestId('ship-create-continue-button')", "QUOTE_UNAVAILABLE", ); expect(msg).toContain("自动化操作超时"); expect(msg).toContain("创建货件/报价表单控件"); expect(msg).not.toBe("暂时无法获取报价,请稍后重试"); }); it("RpaDataInvalidError 映射为 RPA_DATA_INVALID 并保留中文原因", () => { expect(resolveQuoteFailureCode(new RpaDataInvalidError("缺少标准档报价"))).toBe( "RPA_DATA_INVALID", ); expect( resolveQuoteFailureMessage( new RpaDataInvalidError("缺少标准档报价"), "RPA_DATA_INVALID", ), ).toMatch(/标准档|报价/); }); it("含 rate-card 的中文业务句仍可展示", () => { expect( isChineseUserFacingMessage("登录态 rate-card 未能解析出承运商报价"), ).toBe(true); expect( toChineseUserFacingMessage( "登录态 rate-card 未能解析出承运商报价", "RPA_DATA_INVALID", ), ).toContain("承运商报价"); }); it("合格中文原文保留", () => { expect( formatQuoteErrorMessage("QUOTE_UNAVAILABLE", "该线路暂无可用运力,请换地址"), ).toBe("该线路暂无可用运力,请换地址"); }); it("formatQuoteErrorMessage 按 code 回退", () => { expect(formatQuoteErrorMessage("QUOTE_TIMEOUT")).toContain("420 秒"); }); it("PROVIDER_LOGIN_FAILED 统一用户文案", () => { expect( resolveQuoteFailureCode( new RpaError("PROVIDER_LOGIN_FAILED", "内部细节"), ), ).toBe("PROVIDER_LOGIN_FAILED"); expect( resolveQuoteFailureMessage( new RpaError("SESSION_EXPIRED", "仍停在登录页,账密可能错误"), "SESSION_EXPIRED", ), ).toContain("即时保存更新"); expect(formatQuoteErrorMessage("PROVIDER_LOGIN_FAILED")).toContain( "账号或密码可能不正确", ); expect( formatQuoteErrorMessage( "RPA_DATA_INVALID", "FLOCK_LOGIN_FAILED:账号或密码错误", ), ).toContain("即时保存更新"); }); it("英文官网文案译为中文", () => { expect(translateKnownEnglishPhrases("No rates found")).toBe( "未找到可用报价", ); expect( toChineseUserFacingMessage("No carriers available for this lane", "CARRIER_NO_CAPACITY"), ).toBe("该线路暂无可用运力"); }); it("附加服务 appointment 超时译为可读中文,不再吞成通用文案", () => { const msg = toChineseUserFacingMessage( "locator.waitFor: Timeout 8000ms exceeded.\nCall log:\n - waiting for getByTestId('address-book-accessorials-option-appointment').first() to be visible", "QUOTE_UNAVAILABLE", ); expect(msg).toContain("自动化操作超时"); expect(msg).toMatch(/预约|附加服务/); expect(msg).not.toBe("暂时无法获取报价,请稍后重试"); }); it("附加服务不可用业务文案原样保留", () => { const raw = "派送附加服务「appointment」在官网下拉中不可用或未展开(可见选项:liftgate)。请取消该附加服务后重试,或确认地址类型是否支持。"; expect(toChineseUserFacingMessage(raw, "CARRIER_NO_CAPACITY")).toBe(raw); }); });