NodeJS 如何在Jest afterAll钩子中关闭Express服务器

oiopk7p5  于 2023-06-29  发布在  Node.js
关注(0)|答案(3)|浏览(170)

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

qfe3c7zg1#

我在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来为测试主体中的每个测试分别设置timeout和settimeout。

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

mzsu5hc02#

根本原因是Express应用服务器在测试完成后仍在运行。解决方案是关闭服务器。
在主服务器文件中:

export const server = app.listen(...)

在测试文件中:

import { server } from './main-server-file'

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

使用nodejs 17.4.0,jest 27.5.1,supertest 6.2.2。使用cross-env NODE_OPTIONS=--experimental-vm-modules NODE_ENV=test jest运行测试

p1iqtdky

p1iqtdky3#

上面的答案对我不起作用。我用这种方式修复了它:
在主服务器文件中,我添加了这个函数来关闭服务器:

app.closeServer = () => {
  server.close();
};

然后我在测试代码中使用了它,代码块如下:

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

相关问题