Response.error() 不触发 fetch 的 catch 分支,因它返回合法但 type 为 "error" 的 Response;需 mock fetch 抛异常或用 AbortController 才能真实模拟网络故障。

直接用 Response.error() 模拟网络故障是可行的,但它本身不会触发 fetch 的 catch 分支,因为它是合法的 Response 实例(状态码为 0,type 为 "error"),而 fetch 只在真正网络失败(如 DNS 失败、连接中断)时才拒绝 Promise。要真正测试错误处理逻辑,需结合 window.fetch 的 mock 机制来拦截请求并抛出异常。
理解 Response.error() 的真实行为
Response.error() 返回一个 type 为 "error"、status 为 0、statusText 为空字符串的 Response 对象。它不会让 fetch Promise 被 reject,而是正常 resolve 这个 error Response。如果你的代码只检查 response.ok 或 response.status >= 400,它不会进入错误分支——因为 status 是 0,既不 ok,也不符合常规 HTTP 错误判断逻辑。
- ✅ 它适合测试你手动调用
response.clone().error()或显式处理 type === "error" 的边界场景 - ❌ 它不适合模拟“请求根本发不出去”的典型网络故障(如离线、跨域拒绝、AbortError)
正确模拟网络故障的两种主流方式
真正覆盖健壮性测试,应模拟 fetch 被 reject 的情形:
-
方式一:Mock window.fetch 并 throw Error
在测试前覆盖全局 fetch,直接抛出 TypeError、AbortError 或自定义错误:global.fetch = jest.fn(() => Promise.reject(new TypeError("Failed to fetch"))) -
方式二:使用 AbortController 主动中止
在测试中创建const controller = new AbortController(),传入{ signal: controller.signal },然后立即调用controller.abort()。这会触发AbortError,与真实用户点击取消或页面卸载行为一致。
配套断言建议:不止看是否报错
健壮测试要验证整个错误链路是否按预期响应:
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
立即学习“前端免费学习笔记(深入)”;
- 确认你的函数调用后,是否调用了错误回调(如
onError)、是否更新了 loading 状态、是否设置了 error message - 若使用 React + React Query / SWR,检查
error字段是否非 null,isError是否为 true - 避免只断言
expect(...).rejects.toThrow(),而应断言副作用(如 setState 调用次数、UI 文本内容)
一个小而完整的 Jest 示例
假设你有这样一个工具函数:
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
对应测试可写为:
test("fetchUser rejects on network failure", async () => {
global.fetch = jest.fn(() => Promise.reject(new TypeError("Network error")));
await expect(fetchUser(123)).rejects.toThrow("Network error");
expect(fetch).toHaveBeenCalledWith("/api/users/123");
});

















