使用Jest与SuperTest时,express.json()导致Jest无法正常退出的问题求助
Jest测试后无法正常退出问题(因express.json()中间件)
问题原因
express.json()中间件底层依赖raw-body库解析请求体,该库会创建可读流处理请求数据。在测试场景中,若请求体的流未被完全消费或正常关闭,会残留未处理的异步资源,导致Jest判定仍有活跃异步操作,无法自动退出。
解决建议
每次测试后关闭Express服务器/应用
Express实例本身没有close方法,需保存服务器启动后的实例,在测试收尾时关闭:// app.ts import express, { Application } from 'express'; import http from 'http'; export const app: Application = express(); app.use(express.json()); // 仅在非测试环境启动服务器 export let server: http.Server | undefined; if (process.env.NODE_ENV !== 'test') { server = app.listen(3000, () => console.log('Server running')); }在测试文件中添加
afterAll钩子关闭服务器:import request from 'supertest'; import { app, server } from '../../app'; import { endpoints } from '../endpoints'; describe('Registration', () => { afterAll(async () => { await server?.close(); }); test('should create a new user', (done) => { request(app) .post(endpoints.authentication.register) .expect('Content-Type', /json/) .send({ username: 'test', email: 'test@test.com', password: 'test' }) .expect(200) .expect(res => { expect(res.body.status).toBe(200); expect(res.body.message).toBe('OK'); expect(res.body.payload).toEqual({}); }) .end(err => err ? done(err) : done()); }); });改用async/await替代done回调
回调写法容易因嵌套逻辑导致资源泄漏,换成async/await更易控制异步流程:test('should create a new user', async () => { const res = await request(app) .post(endpoints.authentication.register) .expect('Content-Type', /json/) .send({ username: 'test', email: 'test@test.com', password: 'test' }) .expect(200); expect(res.body).toEqual({ status: 200, message: 'OK', payload: {}, }); });避免直接修改响应对象
原测试中直接赋值res.body = {...}会干扰SuperTest的内部流处理逻辑,改用断言验证响应内容即可:.expect(res => { expect(res.body.status).toBe(200); expect(res.body.message).toBe('OK'); expect(res.body.payload).toEqual({}); })用--detectOpenHandles排查其他资源泄漏
运行测试时添加该参数,可定位所有未关闭的异步资源:cross-env NODE_ENV=test jest --detectOpenHandles根据输出结果清理残留的数据库连接、定时器等资源。
内容的提问来源于stack exchange,提问作者Luigi Gargioni
相关产品推荐
相关产品推荐

