Jest+React测试API调用报错:无法读取undefined的json属性
解决Jest Mock Fetch时的
Cannot read properties of undefined (reading 'json')错误 问题重现
测试React组件MyButton时,为验证点击按钮触发的API调用,Mock了全局fetch方法,但运行测试时出现如下报错:
console.log
API call failed TypeError: Cannot read properties of undefined (reading 'json')
相关代码如下:
MyButton.js
const MyButton = ({ incrementFn, decrementFn }) => { const apiFunction = async () => { const dataToSend = { key: 'value' }; try { const response = await fetch('https://api.example/data', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(dataToSend), }); const data = await response.json(); console.log(data); return data; } catch (error) { console.log('API call failed', error); } }; return ( <div> <button onClick={apiFunction} data-testid="apiButton">API</button> <h1>value</h1> </div> ) }; export default MyButton;
原测试代码(button.test.js)
import { render, screen, fireEvent, waitFor } from '@testing-library/react' import MyButton from './MyButton' const fakeData = { name: "Joni Baez", age: "32", address: "123, Charming Avenue" }; global.fetch = jest.fn().mockImplementation(() => { Promise.resolve({ ok: true, json: () => Promise.resolve(fakeData), }) }); afterEach(() => { jest.clearAllMocks(); }); describe('<MyButton/>', () => { it('calls API mock', async () => { render(<MyButton/>); const apiButton = screen.getByTestId('apiButton'); fireEvent.click(apiButton); await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1)); expect(fetch).toHaveBeenCalledWith('https://api.example/data', expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json', }, })); }) })
错误原因
你的fetch Mock实现存在问题:mockImplementation中的函数没有返回Promise对象,导致await fetch(...)得到的结果是undefined,后续调用response.json()自然会抛出“读取undefined的json属性”的错误。
修复方法
有两种简单的修复方式:
方式1:给Mock函数添加return语句
在mockImplementation的函数里返回Promise.resolve的对象:
global.fetch = jest.fn().mockImplementation(() => { // 加上return,返回Promise对象 return Promise.resolve({ ok: true, json: () => Promise.resolve(fakeData), }) });
方式2:使用mockResolvedValue简化Mock
Jest提供了mockResolvedValue方法,可以更简洁地Mock异步函数的返回值:
global.fetch = jest.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(fakeData), });
修复后的完整测试代码
import { render, screen, fireEvent, waitFor } from '@testing-library/react' import MyButton from './MyButton' const fakeData = { name: "Joni Baez", age: "32", address: "123, Charming Avenue" }; // 使用mockResolvedValue简化Mock实现 global.fetch = jest.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(fakeData), }); afterEach(() => { jest.clearAllMocks(); }); describe('<MyButton/>', () => { it('calls API mock', async () => { render(<MyButton/>); const apiButton = screen.getByTestId('apiButton'); fireEvent.click(apiButton); await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1)); expect(fetch).toHaveBeenCalledWith('https://api.example/data', expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json', }, })); // 可选:验证response.json()是否被调用 const mockResponse = await fetch(); expect(mockResponse.json).toHaveBeenCalled(); }) })
内容的提问来源于stack exchange,提问作者yjyjy131
相关产品推荐
相关产品推荐

