I am going to test the components below through the jest and react test library.
I want to test if the API is called normally when I press the button, So I made the API calling part mock.
However, this error appears.
console.log
API call failed TypeError: Cannot read properties of undefined (reading 'json')
I tried because there was advice to remove the .json() part from wait response.json(); but failed to resolve the error.
Below is the detailed code.
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',
},
}));
})
})
2
Answers
you are encountering the error, because when firing the apibutton click, the actual fetch function is trying to be executed, and not the mock.
To implement the mock properly, you should have to files for your button component–> one for just rendering the UI (index.jsx), and the other for handling functionalities (ButtonHandler.jsx). Then you can pass the functions from handler to index as props. Thus, when you render the index, you can replace the button functionality as a mock function.
Maybe a typo, you didn’t return the
Promise
in themockImplementation
method.