UNPKG

@ingeze/api-error

Version:

A TypeScript library for handling HTTP errors in Express, NestJS, and Fastify APIs.

258 lines (257 loc) 7.18 kB
import { describe, beforeEach, it, expect, jest } from "@jest/globals"; import { ErrorHandler } from "../../errors/index.js"; import { expressErrorMiddleware } from "../../handlers/express.js"; import { ZodError } from "zod"; describe("expressErrorMiddleware", () => { let req; let res; let next; beforeEach(() => { req = {}; res = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis(), headersSent: false }; next = jest.fn(); }); it("should handle custom ErrorHandler instances", () => { const customError = new ErrorHandler("Custom error", 400, "CUSTOM_ERROR", { id: 1, info: "Custom error" }); expressErrorMiddleware(customError, req, res, next); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith({ result: customError.toJSON(), data: null, pagination: null }); expect(next).not.toHaveBeenCalled(); }); it("should handle generic errors with 500 status", () => { const genericError = new Error("Something went wrong"); expressErrorMiddleware(genericError, req, res, next); expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 500, type: "INTERNAL_SERVER_ERROR", message: "An unexpected error occurred" }, data: null, pagination: null }); expect(next).not.toHaveBeenCalled(); }); it("should handle ZodError with validation formatting", () => { const issues = [ { code: "invalid_type", expected: "string", received: "undefined", path: ["email"], message: "Email is not valid" }, { code: "invalid_type", expected: "string", received: "undefined", path: ["password"], message: "Password is required" } ]; const zodError = new ZodError(issues); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: { email: ["Email is not valid"], password: ["Password is required"] } } }, data: null, pagination: null }); expect(next).not.toHaveBeenCalled(); }); it("should handle ZodError with empty issues array", () => { const zodError = new ZodError([]); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: {} } }, data: null, pagination: null }); }); it("should handle ZodError without path property", () => { const issues = [ { code: "custom", path: [], message: "General validation error" } ]; const zodError = new ZodError(issues); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: { unknown: ["General validation error"] } } }, data: null, pagination: null }); }); it("should call next() when headers are already sent", () => { const error = new Error("Test error"); res.headersSent = true; expressErrorMiddleware(error, req, res, next); expect(next).toHaveBeenCalledWith(error); expect(res.status).not.toHaveBeenCalled(); expect(res.json).not.toHaveBeenCalled(); }); it("should handle ZodError with multiple errors for same field", () => { const issues = [ { code: "too_small", minimum: 1, type: "string", inclusive: true, exact: false, path: ["username"], message: "Username is required" }, { code: "too_small", minimum: 3, type: "string", inclusive: true, exact: false, path: ["username"], message: "Username must be at least 3 characters" } ]; const zodError = new ZodError(issues); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: { username: ["Username is required", "Username must be at least 3 characters"] } } }, data: null, pagination: null }); }); it("should handle ZodError with nested path", () => { const issues = [ { code: "invalid_type", expected: "number", received: "string", path: ["user", "profile", "age"], message: "Age must be a number" } ]; const zodError = new ZodError(issues); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: { user: ["Age must be a number"] } } }, data: null, pagination: null }); }); it("should handle mixed ZodError issues correctly", () => { const issues = [ { code: "invalid_string", validation: "email", path: ["email"], message: "Invalid email format" }, { code: "invalid_type", expected: "string", received: "undefined", path: ["password"], message: "Password is required" }, { code: "custom", path: ["email"], message: "Email already exists" }, { code: "too_small", minimum: 1, type: "number", inclusive: true, exact: false, path: ["age"], message: "Age must be positive" } ]; const zodError = new ZodError(issues); expressErrorMiddleware(zodError, req, res, next); expect(res.status).toHaveBeenCalledWith(422); expect(res.json).toHaveBeenCalledWith({ result: { success: false, statusCode: 422, type: "VALIDATION", message: "Validation error", details: { errors: { email: ["Invalid email format", "Email already exists"], password: ["Password is required"], age: ["Age must be positive"] } } }, data: null, pagination: null }); }); }); //# sourceMappingURL=express.test.js.map