在 jest 或 vitest 中测试被 reject 的 promise,必须用 await expect(fn()).rejects... 或 try/catch 显式处理,避免未捕获拒绝导致测试失败,并支持校验错误类型、消息或结构。

在 Jest 或 Vitest 中测试被 reject 的 Promise,核心是**不让异常未捕获导致测试失败**,同时能**检查错误类型、消息或结构**。不能直接用 expect(fn()).rejects... 以外的方式“抛出就断言”,必须显式处理 rejection。
✅ 正确方式:用 .rejects 匹配器(推荐)
这是最简洁、语义最清晰的方法,适用于被测函数返回 Promise 的场景:
- 确保函数调用后返回一个 Promise(不是内部 throw)
- 用
await expect(fn()).rejects启动断言链 - 可接
.toThrow(...)、.toEqual(...)、.toMatch(...)等
示例(Vitest / Jest 通用):
test('fetchUser 失败时返回 404 错误', async () => {
// mock 接口返回失败响应
vi.mock('./api', () => ({
fetchUser: () => Promise.reject(new Error('Network Error')),
}));
await expect(fetchUser()).rejects.toThrow('Network Error');
// 或更精确:
await expect(fetchUser()).rejects.toEqual(expect.any(Error));
await expect(fetchUser()).rejects.toMatchObject({ message: 'Network Error' });
});
⚠️ 常见错误:直接 await 一个 reject 的 Promise
下面写法会导致测试直接失败(Unhandled promise rejection),不可用:
// ❌ 错误!会触发 unhandledrejection,测试报红
test('bad way', async () => {
await fetchUser(); // 如果它 reject,这里就崩了
});
原因:async 函数中 await 一个被 reject 的 Promise,若没 try/catch,就会变成未处理拒绝,Jest/Vitest 默认中断测试。
? 替代方案:try/catch + expect
当需要更复杂的错误校验逻辑,或被测代码不直接返回 Promise(比如调用了回调),可用手动捕获:
test('handle error in catch block', async () => {
try {
await fetchUser();
fail('应该抛错'); // 若没抛错,主动让测试失败
} catch (err) {
expect(err).toBeInstanceOf(Error);
expect(err.message).toContain('Failed to fetch');
}
});
注意:fail() 是 Jest/Vitest 提供的辅助方法;Vitest 中也可用 assert.fail(),Jest 推荐用 expect.unreachable()(v29+)或自定义提示。
? 拦截 HTTP 请求并模拟 reject(如使用 fetch)
真实异步常涉及网络请求。用 vi.mock('node:fs') 或 msw / fetch-mock 不够直观;推荐直接 mock fetch:
test('fetch rejects with 500', async () => {
// 拦截全局 fetch,让它返回 rejected Promise
global.fetch = vi.fn(() => Promise.reject(new TypeError('Failed to fetch')));
await expect(myApiCall()).rejects.toThrow('Failed to fetch');
expect(fetch).toHaveBeenCalledTimes(1);
});
注意:mock 后记得清理(vi.unmock('...') 或用 beforeEach/vi.resetAllMocks()),避免污染其他测试。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











