Jest异步测试忽略expect(),Express服务测试超时问题排查
看起来你遇到了一个有点矛盾的问题:明明请求已经成功返回了Hello World(从console.log能看到),但Jest却超时了,仿佛没检测到测试完成。结合你的代码和现象,我来拆解一下可能的原因和解决办法:
核心原因分析
你的测试超时并不是因为请求没完成,而是Jest的事件循环里还有未处理的异步操作,导致它无法判断测试是否真正结束。具体可能出在两个环节:服务器启动的事件监听,或者服务器关闭的异步处理。
解决方案
1. 确保app_started事件被正确触发
你的serverStart Promise依赖于app_started事件来resolve,但如果你的server.js里没有在服务器启动成功后触发这个事件,beforeAll会一直处于等待状态——哪怕服务器已经实际启动并能处理请求,Jest的测试流程还是会被阻塞,最终触发超时。
检查你的server.js,确保在服务器启动回调里触发事件:
const express = require('express'); const app = express(); // 你的路由和中间件配置 app.get("/", (req, res) => { res.send("Hello World"); }); // 启动服务器并触发app_started事件 const server = app.listen(3000, () => { console.log('Server is running on port 3000'); server.emit('app_started'); // 关键:必须触发这个事件,让beforeAll的Promise resolve }); module.exports = server;
2. 正确等待服务器关闭完成
server.close()是异步操作,默认情况下afterAll不会等待它完成。如果服务器还在监听端口,Jest的事件循环里会有活跃的连接,导致它无法退出,最终超时。
修改afterAll,用Promise包裹等待关闭完成:
afterAll(async () => { await new Promise((resolve) => { server.close(resolve); // 等待服务器关闭的回调触发后再resolve }); });
3. 检查是否有其他未处理的异步资源
如果你的服务器里还有其他异步操作在运行(比如未关闭的数据库连接、定时器、WebSocket连接等),这些都会让Jest的事件循环不为空,导致测试无法结束。
比如如果有数据库连接,要在afterAll里添加关闭逻辑;如果有定时器,要在测试前清除。
4. 简化测试的服务器启动逻辑(可选)
如果你不需要监听自定义的app_started事件,可以直接用supertest包裹express app,它会自动处理服务器的临时启动和关闭,避免手动管理事件和关闭逻辑:
const supertest = require("supertest"); const app = require("../app.js"); // 直接导出express app实例,而不是server let request; beforeAll(() => { request = supertest(app); }); describe("When testing the server.js", () => { it("Should connect successfully and be able to return a response", async () => { const response = await request .get("/") .set("Authorization", `bearer ${process.env.AUTHTOKEN}`); expect(response.text).toBe("Hello World"); }); });
这样可以省去手动管理服务器启动事件和关闭的麻烦,减少出错的可能。
内容的提问来源于stack exchange,提问作者Jackster

