Jest测试提前退出:含async.waterfall的方法未执行、调用次数为0如何解决
问题根因
- 你错误混用了
async/await语法和回调风格逻辑:async.waterfall本身是回调驱动的异步流程控制方法,你虽然将outletInfoHelper.fetchAllOutletsByUserIdAndCityId声明为async函数,但没有等待async.waterfall执行完成就返回了,导致外层await实际没有等待业务逻辑执行完成就进入了断言步骤,此时res.send还未被调用,所以报错调用次数为0。 outletInfoHelper的async.waterfall最终回调中,没有调用你传入的outerCallback参数,就算waterfall执行完成,controller中传入的回调逻辑也不会触发。
解决办法
首先将async.waterfall包装为Promise,让异步流程可以被await正确等待,改造后的helper代码如下:
outletInfoHelper.fetchAllOutletsByUserIdAndCityId = function (userId, cityId) { // 手动返回Promise控制异步状态,无需额外加async关键字 return new Promise((resolve, reject) => { async.waterfall( [ function getRestaurantsByUserId(callback) { // 原有逻辑保持不变 }, function getRestaurantsDetails(restIds, callback) { // 原有逻辑保持不变 }, function getRestaurantsUserCount(restaurants, callback) { // 原有逻辑保持不变 } ], function (error, results) { if (error) return reject(error); resolve(results); }); }) }
然后改造controller代码,移除回调嵌套,直接用async/await处理返回结果:
outletInfoController.fetchAllOutletsByUserIdAndCityId = async function (req, res) { try { const userId = req.body.userId; const cityId = req.body.cityId; const result = await outletInfoHelper.fetchAllOutletsByUserIdAndCityId(userId, cityId); responseUtils.buildAndRespond( commonConst.CODE.SUCCESS_RESPONSE_CODE, commonConst.MESSAGE.SUCCESS_RESPONSE_MESSAGE, null, result, res ); } catch (error) { responseUtils.buildAndRespond( commonConst.CODE.FAILURE_RESPONSE_CODE, commonConst.MESSAGE.FAILURE_RESPONSE_MESSAGE, error, null, res ); } };
改造完成后,测试代码中的await outletInfoController.fetchAllOutletsByUserIdAndCityId(req, res)会等待所有异步逻辑执行完成,res.send已经被调用,断言即可正常通过。
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

