import { describe, it, expect } from "vitest"; import { ApplicationError, ValidationError, UnauthorizedError, ChildNotBoundError, NotFoundError, ConflictError, BusinessError, BadGatewayError, GatewayTimeoutError, ServiceUnavailableError, InternalError, } from "../../src/shared/errors/application-error.js"; describe("ApplicationError 体系", () => { describe("ValidationError", () => { it("statusCode 为 400", () => { const err = new ValidationError("参数错误"); expect(err.statusCode).toBe(400); expect(err.code).toBe("BFF_PARENT_VALIDATION_ERROR"); expect(err.type).toBe("validation"); expect(err.message).toBe("参数错误"); }); it("携带 details", () => { const err = new ValidationError("参数错误", { field: "name" }); expect(err.details).toEqual({ field: "name" }); }); }); describe("UnauthorizedError", () => { it("statusCode 为 401", () => { const err = new UnauthorizedError("未授权"); expect(err.statusCode).toBe(401); expect(err.code).toBe("BFF_PARENT_UNAUTHORIZED"); }); }); describe("ChildNotBoundError", () => { it("statusCode 为 403", () => { const err = new ChildNotBoundError("parent-001", "student-999", [ "student-001", "student-002", ]); expect(err.statusCode).toBe(403); expect(err.code).toBe("BFF_PARENT_CHILD_NOT_BOUND"); expect(err.type).toBe("child_not_bound"); expect(err.details).toEqual({ parentId: "parent-001", requestedChildId: "student-999", boundChildren: ["student-001", "student-002"], }); }); it("message 包含 parentId 和 childId", () => { const err = new ChildNotBoundError("parent-001", "student-999", []); expect(err.message).toContain("student-999"); expect(err.message).toContain("parent-001"); }); }); describe("NotFoundError", () => { it("statusCode 为 404", () => { const err = new NotFoundError("Parent", "parent-999"); expect(err.statusCode).toBe(404); expect(err.code).toBe("BFF_PARENT_NOT_FOUND"); expect(err.message).toContain("Parent"); expect(err.message).toContain("parent-999"); }); }); describe("ConflictError", () => { it("statusCode 为 409", () => { const err = new ConflictError("冲突"); expect(err.statusCode).toBe(409); expect(err.code).toBe("BFF_PARENT_CONFLICT"); }); }); describe("BusinessError", () => { it("statusCode 为 422", () => { const err = new BusinessError("业务错误"); expect(err.statusCode).toBe(422); expect(err.code).toBe("BFF_PARENT_BUSINESS_ERROR"); }); }); describe("BadGatewayError", () => { it("statusCode 为 502", () => { const err = new BadGatewayError("下游错误"); expect(err.statusCode).toBe(502); expect(err.code).toBe("BFF_PARENT_BAD_GATEWAY"); }); }); describe("GatewayTimeoutError", () => { it("statusCode 为 504", () => { const err = new GatewayTimeoutError("超时"); expect(err.statusCode).toBe(504); expect(err.code).toBe("BFF_PARENT_GATEWAY_TIMEOUT"); }); }); describe("ServiceUnavailableError", () => { it("statusCode 为 503", () => { const err = new ServiceUnavailableError("不可用"); expect(err.statusCode).toBe(503); expect(err.code).toBe("BFF_PARENT_SERVICE_UNAVAILABLE"); }); }); describe("InternalError", () => { it("statusCode 为 500", () => { const err = new InternalError("内部错误"); expect(err.statusCode).toBe(500); expect(err.code).toBe("BFF_PARENT_INTERNAL_ERROR"); }); }); describe("toJSON", () => { it("序列化为 ActionState 信封格式", () => { const err = new ValidationError("参数错误", { field: "name" }); err.traceId = "trace-001"; const json = err.toJSON(); expect(json.success).toBe(false); // 从 unknown 转换:toJSON 返回 Record const error = json.error as { code: string; message: string; details: unknown; traceId?: string; }; expect(error.code).toBe("BFF_PARENT_VALIDATION_ERROR"); expect(error.message).toBe("参数错误"); expect(error.details).toEqual({ field: "name" }); expect(error.traceId).toBe("trace-001"); }); it("无 traceId 时序列化正常", () => { const err = new NotFoundError("Child", "child-999"); const json = err.toJSON(); expect(json.success).toBe(false); // 从 unknown 转换:toJSON 返回 Record const error = json.error as { traceId?: string }; expect(error.traceId).toBeUndefined(); }); }); describe("继承关系", () => { it("所有错误继承自 ApplicationError", () => { const errors = [ new ValidationError(""), new UnauthorizedError(""), new ChildNotBoundError("", "", []), new NotFoundError("", ""), new ConflictError(""), new BusinessError(""), new BadGatewayError(""), new GatewayTimeoutError(""), new ServiceUnavailableError(""), new InternalError(""), ]; for (const err of errors) { expect(err).toBeInstanceOf(ApplicationError); expect(err).toBeInstanceOf(Error); } }); it("name 属性为构造函数名", () => { expect(new ValidationError("").name).toBe("ValidationError"); expect(new ChildNotBoundError("", "", []).name).toBe( "ChildNotBoundError", ); }); }); });