【问题标题】:How to close Express server inside Jest afterAll hook如何在 Jest afterAll 挂钩中关闭 Express 服务器
【发布时间】:2020-03-19 13:10:40
【问题描述】:

我正在尝试使用 Jest 为我的 Express 服务器编写集成测试。由于 Jest 并行运行测试(并且我想避免使用 --runInBand 按顺序运行测试),因此我使用 get-port 库来查找随机可用端口,以便不同的测试套件不会发生端口冲突。

我的测试都运行成功,唯一的问题是服务器未能在afterAll 挂钩内正确关闭。这会导致 Jest 在控制台中打印以下内容...

Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests.
Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.

当我使用--detectOpenHandles 标志时,Jest 只是在测试完成后挂起。控制台不会打印任何内容。

这是我的测试代码...

let axios = require('axios')
const getPort = require('get-port')
const { app } = require('../../index')
const { Todo } = require('../../models')

// set reference to server to access
// from within afterAll hook
let server

beforeAll(async () => {
  const port = await getPort()
  axios = axios.create({ baseURL: `http://localhost:${port}` })
  server = app.listen(port)
})

afterAll(() => {
  server.close()
})

describe('GET /todos', () => {
  it('returns a list of todos', async () => {
    const { data: todos } = await axios.get('/todos')
    todos.forEach(todo => {
      expect(Todo.validate(todo)).toEqual(true)
    })
  })
})

【问题讨论】:

  • 我建议您使用 supertest,然后您就不需要手动执行此操作(另外,您可以获得一个很好的 API 来发出请求和断言响应)。
  • supertest 的这个问题是我首先尝试切换到 axios 的全部原因...github.com/visionmedia/supertest/issues/…
  • 啊,对不起。不幸的是,您再次遇到同样的问题试图逃避它!
  • 开始认为这可能是 Jest 本身的问题。在这里打开了一个问题...github.com/facebook/jest/issues/9227

标签: node.js express jestjs axios integration-testing


【解决方案1】:

我在这个问题上的 github 线程上。这正是适合我的配置。在 package.json 中

"test": "jest --no-cache  --detectOpenHandles --runInBand --forceExit",

这是测试文件中的配置

afterEach(async () => {
  await server.close();
});

afterAll(async () => {
  await new Promise(resolve => setTimeout(() => resolve(), 10000)); // avoid jest open handle error
});

beforeEach(() => {
  // eslint-disable-next-line global-require
  server = require('../index');
  jest.setTimeout(30000);
});

或者你只有 afterAll 为测试正文中的每个测试单独设置超时和设置超时。这是下面的示例

afterEach(async () => {
  await server.close();
});

afterAll(async () => {
  await new Promise(resolve => setTimeout(() => resolve(), 10000)); // avoid jest open handle error
});

beforeEach(() => {
  // eslint-disable-next-line global-require
  server = require('../index');
});


describe('POST /customers', () => {
  jest.setTimeout(30000);
  test('It creates a customer', async () => {
    const r = Math.random()
      .toString(36)
      .substring(7);
    const response = await request(server)
      .post('/customers')
      .query({
        name: r,
        email: `${r}@${r}.com`,
        password: 'beautiful',
      });
    // console.log(response.body);
    expect(response.body).toHaveProperty('customer');
    expect(response.body).toHaveProperty('accessToken');
    expect(response.statusCode).toBe(200);
  });
});

【讨论】:

  • 在我看来这太过分了。必须有另一种方式,并且不使用 --runInBand 这违背了 Jest 的精神。如果这确实是解决问题的唯一方法,那么 Jest 本身就有问题。
  • 我猜有。这个关于这个问题的 github 线程已经发布了指向:github.com/visionmedia/supertest/issues/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 2012-11-29
相关资源
最近更新 更多