【问题标题】:Jest await default error handler of express开玩笑等待 express 的默认错误处理程序
【发布时间】:2020-11-04 22:43:16
【问题描述】:

鉴于以下设置:

const express = require("express");
const app = express();

app.get("/", function(req, res, next) {
  // explicitly return an error
  return next("my error");
});

// made this middleware for the example,
// solution should typically also work for express default error handling
app.use(function(error, req, res, next) {
  if (error) {
    res.status(500).send({ error });
    throw new Error(error); // <- how to test this?
  }
  next();
});

app.listen(8080, function() {
  console.log("server running on 8080");
}); //the server object listens on port 8080

对于测试:

const request = require("supertest");
const app = require("../../app.js");

const spy = jest.spyOn(global.console, "error").mockImplementation();

it("throws an error", async done => {
  const res = await request(app).get("/");

  expect(res.status).toBe(500);
  expect(res.error.text).toContain("my error");

  expect(spy).toHaveBeenCalled(); // nothing...

  done();
});

用这个 example code 制作了一个 Codesandbox。不知道如何在其中运行节点测试。

【问题讨论】:

    标签: javascript express jestjs supertest


    【解决方案1】:

    async 不应与done 一起使用,这会导致测试超时,以防无法到达done()

    首先,错误处理程序不应该重新抛出错误,除非它是可重用的路由器实例,应该用另一个处理程序来扩充。如果它是连续的最后一个,它应该捕获其中可能发生的同步和异步错误。

    问题是默认错误处理程序是triggered asynchronously,所以应该特别等待:

    it("throws an error", async () => {
      const spy = jest.spyOn(global.console, "error");
      const res = await request(app).get("/");
    
      expect(res.status).toBe(500);
      expect(res.error.text).toContain("my error");
      await new Promise(resolve = > setTimeout(resolve));
      expect(spy).not.toHaveBeenCalled(); // it really shouldn't
    });
    

    解决此问题的更正确方法是确保错误得到处理:

    it("throws an error", async () => {
      const defaultErrorHandler = jest.fn((err, req, res, next) => {});
    
      app.use(defaultErrorHandler);
      const res = await request(app).get("/");
    
      expect(res.status).toBe(500);
      expect(res.error.text).toContain("my error");
      expect(defaultErrorHandler).not.toHaveBeenCalled();
    });
    

    【讨论】:

    • 太棒了。在我的测试中删除了“完成”。关于错误处理程序。如果它不应该抛出,它应该怎么做?
    • 这是终点。它应该以错误响应并可选择记录它,app.use(function(error, req, res, next) { res.status(500).send({ error }); console.error(error) })if (error) 是多余的,因为那是错误处理程序。如果错误处理程序中可能出现错误,则应使用 try..catch 处理它 - 或者应该有另一个错误处理程序。
    • 啊,明白了。所以没有抛出错误,但(可选)登录它们。完美。
    猜你喜欢
    • 2022-01-13
    • 2020-04-26
    • 2023-02-09
    • 1970-01-01
    • 2021-08-04
    • 2020-01-27
    • 2018-06-11
    • 2016-09-02
    • 2019-05-18
    相关资源
    最近更新 更多