React Native Saga测试出现ReferenceError: fetch is not defined的原因与解决
问题成因
这个报错的核心原因很直白:你在Node.js测试环境里调用了React Native专属的fetch API。
React Native运行环境会全局提供fetch供应用使用,但我们的Saga测试一般是在Node.js环境下执行(比如用Jest),而Node.js本身并没有内置fetch这个API。当测试走到doScan里的fetch调用时,Node找不到这个全局变量,自然就抛出了ReferenceError。
解决方案
根据测试的不同需求,有几种实用的解决方式:
1. 直接Mock doScan函数(推荐,符合Saga测试最佳实践)
Saga测试的核心是验证副作用(比如call、cps)是否按预期触发,而非测试doScan内部的网络请求逻辑。所以我们可以直接Mock整个doScan函数,让它返回预设结果,彻底避开fetch的执行逻辑。
比如在你的测试文件顶部添加Mock:
// 导入doScan所在的模块路径 import { doScan } from '../path/to/your/api/file'; // 用Jest Mock掉doScan jest.mock('../path/to/your/api/file', () => ({ doScan: jest.fn(() => Promise.resolve({ /* 预设的接口返回结果 */ })), }));
这样测试时,call(doScan, logScanResult)只会验证调用参数是否正确,不会真的执行doScan里的fetch代码,自然就不会出现fetch未定义的问题。
2. 给Node环境添加fetch的Polyfill
如果你确实需要在测试中执行真实的doScan逻辑(不推荐,会让测试依赖外部服务且变慢),可以给Node环境安装fetch的Polyfill:
- 首先安装依赖:
npm install node-fetch --save-dev
- 然后在测试文件最顶部导入并挂载到全局:
import fetch from 'node-fetch'; global.fetch = fetch; // 如果你的代码用到了Headers,也一并挂载 global.Headers = fetch.Headers;
或者在Jest配置文件(比如jest.config.js)中,把Polyfill加入setupFiles数组,让所有测试自动加载:
module.exports = { setupFiles: ['./jest.setup.js'], };
然后在jest.setup.js中写入:
import fetch from 'node-fetch'; global.fetch = fetch; global.Headers = fetch.Headers;
3. Mock全局的fetch API
如果不想Mock整个doScan,也可以直接Mock全局的fetch,让它返回模拟的响应:
// 在测试文件顶部 global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ success: true }), // 模拟接口返回的JSON数据 // 若你的toJSON函数需要其他响应属性,按需添加 }) ); global.Headers = jest.fn(() => ({})); // 同时Mock Headers构造函数
这样doScan执行时会调用Mock的fetch,既不会报错,还能验证fetch的调用参数是否符合预期。
内容的提问来源于stack exchange,提问作者Anto

