设置Jest为runInBand后仍遇Supertest端口占用问题
Node单元测试EADDRINUSE错误解决方案
问题背景
使用Supertest+Jest测试Node路由时,反复遇到端口占用错误:
code: 'EADDRINUSE', errno: -4091, syscall: 'listen', address: '::', port: 5000
已尝试配置:
- package.json测试命令:
"test": "jest --verbose --watchAll --runInBand --detectOpenHandles --forceExit --coverage" - 设置
maxWorkers=1
相关代码片段:
index.js
app.use("/api/v1", clinicRoutes); let PORT; process.env.STATUS === "production" ? (PORT = process.env.PROD_PORT) : (PORT = process.env.DEV_PORT); app.listen(PORT, () => { logger.info( `app is running in ${process.env.STATUS} mode, listening on port ${PORT}` ); });
index.test.js
const request = require("supertest"); const app = require("../index"); describe("Test the clinic search API", () => { test("It should respond with a list of clinics", async () => { const response = await request(app) .post("/api/v1/search") .send({ name: "Scratch", state: "California", availableFrom: "01:00", availableTo: "23:00", }) .set("Accept", "application/json"); expect(response.statusCode).toBe(200); expect(response.body).toHaveProperty("data"); expect(Array.isArray(response.body.data)).toBe(true); expect(response.body.data[0]).toHaveProperty("name"); expect(response.body.data[0]).toHaveProperty("state"); expect(response.body.data[0]).toHaveProperty("availability"); expect(response.body.data[0].availability).toHaveProperty("from"); expect(response.body.data[0].availability).toHaveProperty("to"); }); });
解决方法
1. 分离App实例与端口监听逻辑(核心方案)
问题根源:每次运行测试时,require("../index")都会执行app.listen(),导致端口被重复占用。
修改index.js,仅在非测试环境启动监听:
// index.js const express = require('express'); const app = express(); app.use("/api/v1", clinicRoutes); // 仅在非测试环境启动服务 if (process.env.NODE_ENV !== 'test') { let PORT = process.env.STATUS === "production" ? process.env.PROD_PORT : process.env.DEV_PORT; app.listen(PORT, () => { logger.info( `app is running in ${process.env.STATUS} mode, listening on port ${PORT}` ); }); } module.exports = app;
Supertest无需实际启动端口即可直接测试Express实例,这样就不会触发端口占用问题。
2. 为测试环境分配独立端口(可选)
如果测试场景需要启动完整服务,可单独指定测试端口:
- 创建jest.setup.js:
process.env.NODE_ENV = 'test'; process.env.DEV_PORT = '5001'; // 使用与开发/生产环境不同的端口
- 在jest.config.js中引入:
module.exports = { testEnvironment: 'node', setupFiles: ['./jest.setup.js'] };
3. 测试结束后手动关闭服务器(兜底)
若上述方法无效,可在测试生命周期中手动管理服务器:
// index.test.js const request = require("supertest"); const app = require("../index"); let server; beforeAll(() => { // 手动启动服务器并保存引用 server = app.listen(5001); }); afterAll((done) => { // 测试完成后关闭服务器,释放端口 server.close(done); }); describe("Test the clinic search API", () => { // 原有测试用例保持不变 });
4. 清理占用端口的外部进程
检查端口5000是否被其他进程占用:
- macOS/Linux:
lsof -i :5000 # 查看占用进程 kill -9 <PID> # 替换为实际进程ID,强制终止 - Windows:
netstat -ano | findstr :5000 # 查看占用进程ID taskkill /F /PID <PID> # 强制终止进程
内容的提问来源于stack exchange,提问作者Olaiwola Ayoola
相关产品推荐
相关产品推荐

