开玩笑:检查函数是否被 JavaScript/Typescript 中的 class 的特定实例调用

Jest: to check if a function is called by a specific instance of class in JavaScript/Typescript

我正在用 jest 测试一些 express 中间件。

it("should throw 400 error if request.body.id is null", () => {
    const req = { body: { id: null } } as any;
    const res = {} as any;
    const next = jest.fn();
    myMiddleware(req, res, next);

    expect(next).toBeCalledWith(expect.any(ErrorResponse));

    expect(next).toBeCalledWith(
        expect.objectContaining({
            statusCode: 400,
            errCode: "error-0123-2342",
            message: "Field id is missing",
        })
    );
});

我的错误响应:

export class ErrorResponse extends Error {
    public statusCode: number;

    public errCode: string;

    constructor(
        statusCode: number = 500,
        errCode: string = "error-123-1993",
        message: string = "Internal Server Error"
    ) {
        super(message);
        this.statusCode = statusCode;
        this.errCode = errCode;
    }
}

我设法检查是否在 next 函数中调用了具有特定 属性 的 ErrorResponse,但它不能保证 ErrorResponse 对象仅包含 3 个属性(statusCode, errCode, message) 如果有人把ErrorResponse改成多一个属性,比如details.

我想在下面做一些事情并保证 ErrorResponse 对象只包含 3 个属性(statusCodeerrCodemessage)。

it("should throw 400 error if request.body.id is null", () => {
    const req = { body: { id: null } } as any;
    const res = {} as any;
    const next = jest.fn();
    myMiddleware(req, res, next);

    expect(next).toBeCalledWith(
        new ErrorResponse(
            400,
            "error-3123-2332",
            "Field id is missing"
        )
    );
});

请问有没有办法开玩笑的?

粗略浏览了 jest 文档后,expect.extend 似乎可以做你想做的事:

expect.extend({
  toBeErrorResponse(received) {
    if (received instanceof ErrorResponse &&
        Object.keys(received).length === 2)
      return {
        message: () => "expected no ErrorResponse",
        pass: true,
      };
    else
      return {
        message: () => "expected an ErrorResponse",
        pass: false,
      };
  }
});
test("my ErrorResponse", () => {
  const next = jest.fn();
  next(new ErrorResponse(400, "E", "M"));
  expect(next).toBeCalledWith(expect.toBeErrorResponse());
});