纯JavaScript项目中Jest调用fetch报“fetch未定义”求助
嘿,我来帮你拆解这个问题的核心——你困惑的点其实在于对Jest运行环境的误解,咱们一步步来:
问题到底出在哪?
你说的没错,浏览器环境里fetch是默认存在的,但Jest的测试代码是跑在Node.js环境里的,而Node.js在v18版本之前根本没有内置fetch API!这就是你遇到报错的核心原因——你的项目代码在浏览器里能正常跑,但测试代码的执行环境是Node,不是浏览器,自然找不到fetch。
你的Webpack和Babel配置都是给浏览器打包用的,Babel的polyfill只会注入到浏览器代码里,不会自动作用于Jest的测试环境,这也是为什么你觉得明明项目里没问题,测试却报错的原因。
几种可行的解决办法
根据你是想做真实API调用的集成测试,还是模拟调用的单元测试,有不同的方案:
1. 继续用isomorphic-fetch(你已经尝试的方式)
isomorphic-fetch的作用就是在浏览器用原生fetch,在Node环境自动用node-fetch做兼容。你已经安装了它,只需要让Jest的测试环境加载它就行:
- 要么在每个测试文件顶部加:
import 'isomorphic-fetch'; - 要么全局配置,不用每个文件都加:
在package.json的jest配置里加setupFiles:
然后新建"jest": { "transform": { "^.+\\.js?$": "babel-jest" }, "setupFiles": ["./src/setupTests.js"] }src/setupTests.js,写入:
这样所有测试文件都会自动加载fetch的polyfill了。import 'isomorphic-fetch';
2. 直接用node-fetch做全局模拟
如果你不想用isomorphic-fetch,也可以单独装node-fetch,然后把它挂到Node的全局对象上:
先装依赖:
npm install node-fetch --save-dev
然后在setupTests.js里加:
import fetch from 'node-fetch'; global.fetch = fetch;
这样Jest运行时就有全局的fetch了,测试真实API调用就没问题。
3. 正确用jest-fetch-mock解决之前的错误
你之前用jest-fetch-mock遇到JSON解析错误,是因为没正确模拟API的响应!jest-fetch-mock的作用是模拟fetch的返回,不用真的调用API,适合单元测试(速度快、不依赖外部服务)。正确用法是这样的:
先装依赖:
npm install jest-fetch-mock --save-dev
在setupTests.js里启用mock:
import fetchMock from 'jest-fetch-mock'; fetchMock.enableMocks();
然后测试文件这么写:
import { getWordsAPI } from '../src/js/api'; describe('Integration with getWords API', () => { // 每次测试前重置mock,避免相互影响 beforeEach(() => { fetch.resetMocks(); }); test('Get Word List', async () => { // 模拟API返回的JSON数据 fetch.mockResponseOnce(JSON.stringify([ { text: 'hello' }, { text: 'world' } ])); const result = await getWordsAPI(); expect(result).toEqual([ { text: 'hello' }, { text: 'world' } ]); // 还能验证fetch是否被正确调用了 expect(fetch).toHaveBeenCalledWith('https://server-api-address'); }); });
之前的错误是因为你开了mock但没给返回数据,fetch返回空内容,解析JSON自然报错啦。
最后再总结下
- 核心误区:Jest跑在Node环境,不是浏览器,所以没有原生fetch(Node v18+才支持)
- 要真实调用API做集成测试:用isomorphic-fetch或node-fetch做polyfill
- 要做单元测试:用jest-fetch-mock模拟响应,更高效稳定
内容的提问来源于stack exchange,提问作者piecemaker

