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

Bil*_*ill 0 typescript ts-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);
};

Run Code Online (Sandbox Code Playgroud)

损坏的测试给出错误 TypeError: Cannot read property 'send' of undefined

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);
  });
});

Run Code Online (Sandbox Code Playgroud)

以及 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;
  }
}

Run Code Online (Sandbox Code Playgroud)

hoa*_*gdv 5

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

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

我们可以使用 来模拟相同的行为.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();
  });
});
Run Code Online (Sandbox Code Playgroud)