You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:57:19