首页 > 解决方案 > 如何在 Jest afterAll 挂钩中关闭 Express 服务器

问题描述

我正在尝试使用 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)
    })
  })
})

标签: node.jsexpressjestjsaxiosintegration-testing

解决方案


我在这个问题上的那个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);
  });
});

推荐阅读