应使用window.addeventlistener('unhandledrejection')捕获未处理的promise拒绝,确保promise既无.catch()也未被await且无后续处理,事件触发后通过event.reason断言错误内容,并调用event.preventdefault()抑制默认警告。

在 JavaScript 中,未处理的 Promise 拒绝(unhandled rejection)默认不会抛出同步错误,但会触发 unhandledrejection 事件,可能被忽略导致静默失败。测试这类问题,关键是主动触发拒绝并验证是否被正确捕获或是否触发了全局监听器。
使用 window.addEventListener('unhandledrejection') 捕获并断言
这是最直接的测试方式:在测试前注册一次性监听器,然后触发一个未被 catch 或 await 的 Promise 拒绝,检查事件是否如期触发。
示例(用 Jest):
test('should detect unhandled promise rejection', (done) => {
// 监听一次 unhandledrejection
window.addEventListener('unhandledrejection', (event) => {
expect(event.reason).toBeInstanceOf(Error);
expect(event.reason.message).toBe('test error');
done();
}, { once: true });
// 触发未处理的拒绝(不 catch、不 await)
Promise.reject(new Error('test error'));
});
⚠️ 注意:需确保该 Promise 确实“未被处理”——不能有 .catch(),也不能在 async 函数中用 await 后不加 try/catch(否则会被视为已处理)。
在 Node.js 环境中监听 process.on('unhandledRejection')
Node.js 使用不同事件名,且行为略有差异(例如:若未监听,进程可能退出)。测试时需提前注册监听,并确保测试后清理。
- 用
jest.resetModules()或手动removeListener避免监听器残留 - 推荐使用
once选项或在afterEach中移除 - 示例中可配合
jest.useFakeTimers()控制微任务时机(因拒绝在下一个 tick 触发)
用 jest.mock('node:process') 或拦截全局对象(进阶)
若想避免真实触发全局事件(如防止干扰其他测试),可临时 mock process.on 或重写 window.addEventListener:
- 保存原始方法,测试中替换为收集事件的存根函数
- 断言调用次数、参数内容,再恢复原始方法
- 适用于集成测试或对环境敏感的 CI 场景
避免误判:区分“已处理”和“未处理”
以下情况 不算 unhandled rejection,测试时需避开:
-
Promise.reject().catch(() => {})—— 显式捕获 -
async () => { await Promise.reject(); }且调用处有try/catch - 在支持
rejectHandler的测试运行器(如 Vitest)中启用了自动处理
真正未处理的典型场景是:Promise 构造后既没 then/catch,也没被 await,且作用域结束。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











