使用Jest模拟fetch请求时抛出TypeError: Cannot read properties of undefined (reading 'then')
解决Jest模拟fetch时的TypeError问题
错误原因分析
你遇到的TypeError: Cannot read properties of undefined (reading 'then'),本质是fetch调用后返回了undefined,导致无法调用.then()方法。这通常是因为global.fetch的模拟没有被正确挂载,或者测试执行时fetch并未指向你定义的mock函数。同时,即使mock正确,直接在render后断言也会因为异步操作未完成而无法获取更新后的DOM内容。
修复步骤
1. 正确模拟fetch(推荐使用jest.spyOn)
替换直接赋值global.fetch的方式,改用jest.spyOn来模拟,这样能更好地兼容TypeScript类型,同时确保mock被正确挂载:
import { render, waitFor } from "@testing-library/react"; import App from "./App"; describe("App", () => { beforeEach(() => { // 重置并模拟fetch jest.spyOn(global, 'fetch').mockResolvedValue({ json: jest.fn().mockResolvedValue({ value: "This is a test joke" }) } as Response); }); afterEach(() => { // 清理mock,避免影响其他测试 jest.restoreAllMocks(); }); it("loads the joke on mount", async () => { const { container } = render(<App />); // 等待异步操作完成,DOM更新 await waitFor(() => { expect(container.innerHTML).toContain("This is a test joke"); }); }); });
2. 关键说明
- 使用
jest.spyOn替代直接赋值global.fetch:这种方式会保留原对象的类型,避免TypeScript类型断言带来的潜在问题,同时更容易在测试后清理。 - 添加
beforeEach和afterEach:确保每个测试前mock都是全新的,测试后恢复原fetch,防止测试间的副作用。 - 使用
waitFor:因为useEffect中的fetch是异步操作,render后DOM不会立即更新,waitFor会等待断言条件满足后再执行,避免因异步时序问题导致的断言失败。
3. 兼容TypeScript的直接赋值写法(备选)
如果你坚持直接赋值global.fetch,需要确保mock的结构完全符合fetch的类型定义:
global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ value: "This is a test joke" }), ok: true // 添加必要的Response属性 }) as Response );
但这种方式不如jest.spyOn灵活,且容易留下测试污染,更推荐第一种方案。
内容的提问来源于stack exchange,提问作者Ristirianto Adi
相关产品推荐
相关产品推荐

