This minimum working example demonstrates what happens in a smaller test scenario:
src/code.test.js
:
import {useState, useEffect, useCallback} from 'react';
import {render, waitForElementToBeRemoved, fireEvent} from '@testing-library/react';
global.fetch=url=>Promise.resolve({json: ()=>{
return Promise.resolve('test');
}});
const Component = ({callback}) => {
const [serverData, setServerData] = useState(null);
useEffect(()=>{
fetch('/api/get_it').then(r=>r.json()).then(data=>{
setServerData(data);
});
}, []);
if (!callback) {
return <div>No Callback</div>;
}
return <div>Server data: {serverData}</div>;
}
test('without callback', async () => {
const component = render(<Component/>);
component.getByText('No Callback');
});
package.json
:
{
"dependencies": {
"@testing-library/react": "^13.3.0",
"react-scripts": "5.0.1"
},
"scripts": {
"test": "react-scripts test --verbose",
"check": "jest --version"
}
}
When running this (npm i && npm test;
), I get
Warning: An update to Component inside a test was not wrapped in act(...).
...
7 |
8 | const Component = ({callback}) => {
> 9 | const [serverData, setServerData] = useState(null);
| ^
10 |
This is because of the setServerData
call after the fetch
on line 12 is resolved. In this test case, with the missing callback
, I don't care about the serverData
. The naive approach to fixing this would be to add callback
to the dependency array for the useEffect
on line 15. That is not acceptable because that useEffect
should not run again any time callback
changes!
How to solve the "update was not wrapped in act()" warning in testing-library-react? is materially different from that question because in this question, in my code there is nothing to find.
How can I write this test to avoid this warning?
Make sure all state changes are done before proceeding:
let component;
await act(()=>{
component = render(<Component/>);
});
component.getByText('No Callback');
(Import act
from the testing library.)
Now, no matter how many inner fetches, useEffect
s or useEffect
s that trigger other useEffect
s happen, they (and the state changes they cause) will all be done by the time the getByText
runs and the test ends.