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

Supertest报TypeError:无法读取undefined的close属性问题求助

Express集成测试Supertest报错:TypeError: Cannot read properties of undefined (reading 'close')

核心原因

报错本质是两个可能的问题:要么你的src/index.js没有正确导出带有close()方法的HTTP Server实例,要么测试代码中存在模块缓存或异步处理不当,导致afterEach执行时server变量变为undefined。

解决方案

方案1:确保正确导出Server实例

Express的app对象本身没有close()方法,只有app.listen()返回的HTTP Server实例具备该方法。检查并修改你的src/index.js:

// src/index.js
const express = require('express');
const app = express();

// 配置路由、中间件等逻辑...

// 启动服务器并导出Server实例
const server = app.listen(process.env.PORT || 3000, () => {
  console.log('Server running on port:', process.env.PORT || 3000);
});

module.exports = server;

方案2:修复测试中的异步与变量检查问题

server.close()是异步操作,直接调用可能导致测试未等待关闭完成就结束,同时添加存在性判断避免server为undefined:

const request = require('supertest');

let server;

beforeEach(() => {
  server = require('../../../src/index');
});

// 用Promise等待close完成,并添加存在性判断
afterEach(async () => {
  if (server) {
    await new Promise(resolve => server.close(resolve));
    server = undefined; // 重置变量,避免影响后续测试
  }
});

describe('POST', () => {
  it('should check if user sent required parameters', async () => {
    const res = await request(server).post('/users');
    expect(res.status).toBe(400);
  });
});

方案3:拆分App与Server创建(推荐)

将Express app的定义与服务器启动分离,避免Node.js模块缓存导致的重复启动问题:

// src/app.js
const express = require('express');
const app = express();

// 配置路由、中间件等逻辑...

module.exports = app;
// src/index.js
const app = require('./app');
const server = app.listen(process.env.PORT || 3000);
module.exports = server;

测试代码改为每次启动新的Server实例:

const request = require('supertest');
const app = require('../../../src/app');

let server;

beforeEach(() => {
  // 用0让系统分配随机端口,避免端口占用冲突
  server = app.listen(0);
});

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

describe('POST', () => {
  it('should check if user sent required parameters', async () => {
    const res = await request(server).post('/users');
    expect(res.status).toBe(400);
  });
});

关键说明

  • 不要混淆Express的app对象与app.listen()返回的Server实例,只有后者具备close()方法。
  • Node.js会缓存require的模块,多次require同一文件只会执行一次模块代码,直接在模块中启动服务器容易导致测试间的状态污染。
  • 异步操作(如server.close())必须等待完成,否则会导致测试资源未正确释放,影响后续用例。

内容的提问来源于stack exchange,提问作者Rahimi0151

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 10:10:24