Jest使用node-fetch测试通过但检测到开放句柄无法退出如何解决
问题原因
Jest检测到的未关闭句柄本质是node-fetch底层残留的HTTP连接资源,和你猜测的超时无关,主要触发原因有两个:
node-fetch默认开启HTTPkeep-alive,请求完成后空闲连接会暂存在连接池中复用,不会立刻销毁,Jest会将这类活跃的socket连接识别为未关闭句柄。- 你的测试代码仅读取了response的状态码,没有消费response的body流,也没有显式销毁response对象,node-fetch会一直持有该请求关联的资源等待后续操作,导致句柄残留。
可行解决方案
你可以根据场景选择以下任意一种方案解决:
- 方案1:显式配置禁用keep-alive并销毁资源(最推荐,从根源解决问题)
修改测试代码,请求时禁用连接复用,测试完成后销毁response关联的流资源:
test('the VIP json url exists', async () => { const response = await nodeFetch('https://go-vip.net/ip-ranges.json', { // 禁用keep-alive,请求完成后直接关闭连接 agent: false }) try { expect(response.status).toBe(200); } finally { // 销毁response body流,释放所有关联资源 response.body?.destroy(); } });
- 方案2:主动消费response body
就算不需要返回内容,也可以主动消费body流触发资源自动释放:
test('the VIP json url exists', async () => { await nodeFetch('https://go-vip.net/ip-ranges.json') .then(async (r) => { expect(r.status).toBe(200); // 消费body内容,不需要的话可以不用接收返回值 await r.text(); }) .catch((e) => { fail(e); }); });
- 方案3:临时强制Jest退出
如果仅需要快速解决测试执行的报错,不需要修改业务代码,可以在运行jest命令时添加--forceExit参数,所有测试用例执行完成后Jest会直接强制结束进程,忽略残留的未关闭句柄。 - 方案4:全局配置禁用node-fetch的keep-alive
如果项目中有大量使用node-fetch的测试用例,可以在jest的全局setup文件中统一配置node-fetch的默认参数,全局禁用keep-alive,不需要逐个修改测试用例。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

