如何使用 jest 和 TypeScript 测试 express 中间件错误处理程序

How to test express middleware error handler with jest and TypeScript

我对使用 jest 测试中间件完全陌生

中间件

import HttpException from "../common/http-exception";
import { Request, Response, NextFunction } from "express";

export const errorHandler = (
  error: HttpException,
  request: Request,
  response: Response,
  next: NextFunction
) => {
  const status = error.statusCode || error.status || 500;

  response.status(status).send(error);
};

给出错误类型错误的失败测试:无法读取未定义的 属性 'send'

import HttpException from "../src/common/http-exception";
import { NextFunction, Request, Response, response } from "express";
import { errorHandler } from "../src/middleware/error.middleware";

describe("Error handler middleware", () => {
  const error: HttpException = {
    name: "error",
    statusCode: 500,
    status: 1,
    message: "string",
    error: "string"
  };
  let mockRequest: Partial<Request>;
  let mockResponse: Partial<Response>;
  let nextFunction: NextFunction = jest.fn();

  beforeEach(() => {
    mockRequest = {};
    mockResponse = {
      status: jest.fn()
    };
  });

  test("handle error", async () => {
    errorHandler(
      error as HttpException,
      mockRequest as Request,
      mockResponse as Response,
      nextFunction
    );

    expect(response).toBe(500);
  });
});

以及 HttpException 的打字稿

export default class HttpException extends Error {
  statusCode?: number;
  status?: number;
  message: string;
  error: string | null;

  constructor(statusCode: number, message: string, error?: string) {
    super(message);

    this.statusCode = statusCode;
    this.message = message;
    this.error = error || null;
  }
}

在你的处理程序中,你调用 response.status(status).send(error);,这意味着 .status() 应该 return 一个包含 send 函数的对象,但在你的模拟中 status: jest.fn()它将 return undefined.

对于 express 的 Response 对象,它使用链式方法,这意味着函数将 return 对象本身。

我们可以用 .mockReturnThis() 模拟相同的行为。

我也更新了您对中间件的期望:

.spec.ts

describe("Error handler middleware", () => {
  const error: HttpException = {
    name: "error",
    statusCode: 500,
    status: 1,
    message: "string",
    error: "string"
  };
  let mockRequest: Partial<Request>;
  let mockResponse: Partial<Response>;
  let nextFunction: NextFunction = jest.fn();

  beforeEach(() => {
    mockRequest = {};
    mockResponse = {
      status: jest.fn().mockReturnThis(), // This line
      send: jest.fn(), // also mocking for send function
    };
  });

  test("handle error when error includes statusCode", async () => {
    errorHandler(
      error as HttpException,
      mockRequest as Request,
      mockResponse as Response,
      nextFunction
    );

    expect(mockResponse.status).toHaveBeenCalledWith(500);
    expect(mockResponse.send).toHaveBeenCalledWith(error);
    expect(nextFunction).not.toHaveBeenCalled();
  });
});