Node 12升级Node 16后Promise测试用例失败问题
问题根因
- 首先是Node.js版本的默认行为变更:从Node v15开始,所有未挂载catch处理的Promise拒绝默认会直接抛出
ERR_UNHANDLED_REJECTION错误终止进程,而v12及更早版本仅会打印警告不会中断执行,这是版本升级后报错直接暴露的核心背景。 - 你的Mock代码存在悬空的Promise拒绝:Mock响应里的
json方法内部创建了Promise.reject(new Error()),但没有return这个Promise,导致这个被拒绝的Promise完全脱离了后续的Promise调用链,业务代码里挂载的.catch()根本捕获不到它,成了无主的拒绝,刚好触发Node16的报错规则。 - 测试的等待逻辑完全错误:你写的
await thePromise.then().catch()只等待了最外层mock的fetch Promise resolve,没有等待后续response.json()、链式then/catch执行、React状态更新、组件重渲染这些微任务跑完,断言触发时错误状态还没更新到DOM上,自然拿到null快照。之前加的空catch没有任何实际错误处理逻辑,只是碰巧多延迟了一个微任务,完全没解决悬空Promise的核心问题。
修复方案
- 先修复Mock逻辑,让rejected Promise正确进入调用链
把json方法的写法改成直接返回Promise,不要在大括号里创建了Promise又不return,否则这个reject永远不会被业务代码的catch捕获:
// 错误写法:无return,Promise.reject脱离调用链 const thePromise = Promise.resolve({ json: () => { Promise.reject(new Error()); }, }); // 正确写法:返回rejected Promise,让它进入后续链式调用 const thePromise = Promise.resolve({ json: () => Promise.reject(new Error()), });
- 替换错误的等待逻辑,等所有异步操作完成再断言
不要手动await你自己mock的外层Promise,等微任务队列排空、组件完成重渲染后再做快照断言:
it('should test', async () => { const thePromise = Promise.resolve({ json: () => Promise.reject(new Error()), }); validateCode.mockReturnValueOnce(thePromise); const rendered = renderModule({ state: { code: 'mockRefCode' } }); rendered.find('#btn').simulate('click'); // 等待所有Promise链、状态更新的微任务执行完成 await Promise.resolve(); // Enzyme环境需要手动刷新wrapper获取最新DOM rendered.update(); expect(rendered.find('#error')).toMatchSnapshot(); });
如果是用React Testing Library写的测试,直接用waitFor包裹断言即可,不需要手动写等待逻辑,稳定性更高。
修复后,mock的reject会被业务代码的catch正常捕获,触发setValidationError渲染错误提示,也不会存在未处理的Promise拒绝,Node16环境下可以正常跑通测试、匹配正确快照。
内容的提问来源于stack exchange,提问作者karvai
相关产品推荐
相关产品推荐

