MERN项目POST方法单元测试出现‘For async tests and hooks, ensure "done()" is called’错误的排查与解决
解决你的MERN项目POST接口单元测试超时问题
嘿,我看了你的代码和错误信息,这个超时问题主要是几个明显的代码错误导致的,咱们一步步来修复:
核心错误原因分析
1. POST路由处理函数参数顺序完全颠倒(最关键原因)
在routes/products.js的POST路由里,你把Express路由的参数顺序写反了:
// ❌ 错误写法:把err放在第一个参数位 router.post("/product/save", (err, req, res, next) => { ... })
Express路由处理函数的正确参数顺序是(req, res, next),你把错误对象放在首位,导致这个路由永远无法正确接收请求参数、返回响应——请求发出去后一直挂起,最终触发测试超时。
2. 测试文件使用了路由实例而非完整Express应用
你的测试文件post.js里直接导入了路由文件:
const app = require("../../../routes/products.js");
但supertest需要的是完整的Express应用实例,而非单独的路由模块,这会导致测试请求没有正确的应用上下文。
3. 测试断言的拼写错误
测试里的porperty是拼写错误,正确应为property——虽然这不是超时的直接原因,但会导致后续断言失败。
一步步修复步骤
步骤1:修正POST路由的参数顺序
修改routes/products.js里的POST路由,同时建议返回创建的产品数据,方便测试断言:
// ✅ 正确写法 router.post("/product/save", (req, res) => { let newProduct = new Products(req.body); newProduct.save((err) => { if (err) { return res.status(400).json({ error: err, }); } return res.status(200).json({ success: "Product saved successfully", product: newProduct // 返回创建的产品,方便测试验证字段 }); }); });
步骤2:在server.js中导出Express应用实例
修改server.js,添加app的导出,让测试能使用完整的应用:
// ... 其他代码 ... app.listen(PORT, () => { console.log(`App is running on ${PORT}`); }); // 新增app的导出 module.exports = { connect, close, app };
步骤3:修正测试文件的应用导入和断言拼写
修改test/api/products/post.js,同时添加错误捕获避免超时:
const expect = require("chai").expect; const request = require("supertest"); // ✅ 改为导入server.js里的完整app和连接方法 const { app, conn } = require("../../../server.js"); describe("POST /products", () => { before((done) => { conn .connect() .then(() => done()) .catch((err) => done(err)); }); after((done) => { conn .close() .then(() => done()) .catch((err) => done(err)); }); it("OK, creating a new product works", (done) => { request(app) .post("/product/save") .send({ productName: "Mango", description: "description Mango", price: "rs 50", productCategory: "fruits", productUrl: "https://upload.wikimedia.org/wikipedia/commons/9/90/Hapus_Mango.jpg" }) .then((res) => { const body = res.body.product; // 对应路由返回的product字段 // ✅ 修正拼写错误porperty → property expect(body).to.contain.property("_id"); expect(body).to.contain.property("productName"); expect(body).to.contain.property("description"); expect(body).to.contain.property("price"); expect(body).to.contain.property("productCategory"); expect(body).to.contain.property("productUrl"); done(); }) // ✅ 新增catch捕获请求错误,避免测试因未处理的错误超时 .catch(err => done(err)); }); });
可选优化:用async/await简化测试
你可以改用async/await替代done回调,代码更简洁,也不容易遗漏done调用:
it("OK, creating a new product works", async () => { const res = await request(app) .post("/product/save") .send({ productName: "Mango", description: "description Mango", price: "rs 50", productCategory: "fruits", productUrl: "https://upload.wikimedia.org/wikipedia/commons/9/90/Hapus_Mango.jpg" }); const body = res.body.product; expect(body).to.contain.property("_id"); expect(body.productName).to.equal("Mango"); // 其他断言... });
完成这些修改后,你的测试应该就能正常运行了——路由能正确处理POST请求并返回响应,测试也能拿到响应进行断言,不会再出现超时问题。
内容的提问来源于stack exchange,提问作者Nimasha Fernando
相关产品推荐
相关产品推荐

