React组件fetch中AbortController测试本应通过却失败问题
React组件AbortController请求逻辑测试失败修复方案
问题根因
- 组件代码存在变量拼写错误:定义的中断控制器实例名为
abortController,传入fetch的signal配置时错写为ammAbortController.signal,未定义变量会直接触发引用错误。 - 测试等待逻辑不完整:
renderComponent仅等待了组件渲染的act周期,没有等待fetch请求的Promise链(含catch分支)完全执行,jest-circus会提前检测到未被即时处理的Promise拒绝,直接抛出你看到的thrown: Object {name: "AbortError"}报错。 - mock的AbortError不符合真实实现:直接reject普通对象和浏览器真实抛出的AbortError(DOMException实例)存在差异,可能导致分支判断失效。
修复方案
1. 修正组件代码拼写错误
将useEffect中fetch调用的signal参数改为正确的变量引用,同步修复同一段代码里的参数覆盖、构造函数传参错误:
useEffect(() => { const abortController = new AbortController(); const url = 'string' // 修正错误的变量名引用 fetch(url, {signal: abortController.signal}) .then(res => res.json()) .then((data) => { if (!data || !data.result || !Array.isArray(data.result)) { setData([]); return; } // 修正参数名覆盖、传入错误构造参数的问题 const newData = data.result.map(item => new Data(item)); setData(newData); }) .catch(err => { // 兼容不同运行时的AbortError判断 if (err.name === "AbortError" || err.code === DOMException.ABORT_ERR){return} console.error(err); }); return ()=>abortController.abort(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [trigger]);
2. 完善测试用例的等待与mock逻辑
补全微任务等待逻辑,使用更贴近真实场景的AbortError mock,测试结束后恢复mock避免污染其他用例:
import { act, render, waitFor } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; const renderComponent = async () => { await act(async() => { component = await render( <BrowserRouter> <Component runningTest={true}/> </BrowserRouter> ); }) }; it.only('fetch触发AbortError时不会打印控制台错误', async () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(()=>{}); // 模拟真实场景下的AbortError,使用标准DOMException构造 global.fetch = jest.fn(() => { return Promise.reject(new DOMException('Aborted', 'AbortError')); }); await renderComponent(); // 等待所有Promise微任务执行完成,确保catch分支逻辑跑完 await waitFor(() => { expect(errorSpy).toHaveBeenCalledTimes(0); }); // 恢复mock,避免影响其他测试用例 errorSpy.mockRestore(); global.fetch.mockRestore(); });
验证说明
修复后测试会等待fetch的catch分支完整执行,AbortError会被正确捕获并跳过console.error调用,断言可以正常通过,不会再出现jest-circus抛出未处理reject的报错。
内容的提问来源于stack exchange,提问作者Derick Fabert
相关产品推荐
相关产品推荐

