Although I think you are already doing this, the first thing to note is that you shouldn't be actually fetching any data from your tests-- you should be mocking the result.
Once you are doing that, you will use the waitFor
utility to aid in your async testing-- this utility basically accepts a function that returns an expectation (expect
), and will hold at that point of the test until the expectation is met.
Let's provide an example. Take the imaginary component I've created below:
const MyComponent = () => {
const [data, setData] = useState();
useEffect(() => {
MyService.fetchData().then((response) => setData(response));
}, []);
if (!data) {
return (<p>Loading...</p>);
}
// else
return (
<div>
<h1>DATA!</h1>
<div>
{data.map((datum) => (<p>{datum}</p>))}
</div>
</div>
);
}
So for your test, you would do
import MyService from './MyService';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
const mockData = ['Spengler', 'Stanz', 'Venkman', 'Zeddmore'];
beforeEach(() => {
jest.spyOn(MyService, 'fetchData')
.mockImplementation(
() => new Promise((res) => setTimeout(() => res(mockData), 200))
);
});
afterEach(() => {
MyService.fetchData.mockRestore();
});
it('displays the loading first and the data once fetched', async () => {
render(<MyComponent />);
// before fetch completes
expect(screen.getByText(/Loading/)).toBeInTheDocument();
expect(screen.queryByText('DATA!')).toBeNull();
// after fetch completes..
// await waitFor will wait here for this to be true; if it doesn't happen after about five seconds the test fails
await waitFor(() => expect(screen.getByText('DATA!')).toBeInTheDocument());
expect(screen.queryByText(/Loading/)).toBeNull(); // we don't have to await this one because we awaited the proper condition in the previous line
});
});
This isn't tested but something like this should work. Your approach to mocking may vary a bit on account of however you've structured your fetch.
async
and usingawait findBy
instead ofgetBy
did the job. If you feel like answering the question then I'll checkmark it as answer - I guess whoever is first @Sea @Hinton @Tarnetgaronne – Sapota