reactjsjestjsreact-testing-librarysnapshot-testing

How to snapshot-test a component that does async data loading using react-testing-library?


So far, in the projects I'm working on, I usually snapshot-test my components that does async data loading this way:

describe('MyComponent component', () =>{
    test('Matches snapshot', async () => {
        fetch.mockResponse(JSON.stringify(catFacts));

        const { asFragment } = render(<MyComponent />);
        await waitFor(() => expect(asFragment()).toMatchSnapshot());
    })
})

I find it very handy, because it allows to have a snapshot containing the different states of the component (loading, errors, loaded data).

The thing is that I just found out that this method was not recommended at all, and that the latest updates of the @testing-library/react package don't allow me to test my components this way anymore.

According to the eslint rules of the package, I would have to modify my code like this:

describe('MyComponent component', () =>{
    test('Matches snapshot', () => {
        fetch.mockResponse(JSON.stringify(catFacts));

        const { asFragment } = render(<MyComponent />);
        expect(asFragment()).toMatchSnapshot();
    })
})

It works, but the generated snapshot contains only the initial state of the component (in this case, "loading").

How would you do in this situation to efficiently snapshot-test a component loading data asynchronously?


Solution

  • You are on the right track. The only thing left is to wait for your data to be loaded before you make your assertion.

    describe('MyComponent component', async () =>{
        test('Matches snapshot', () => {
            fetch.mockResponse(JSON.stringify(catFacts));
            
            const { asFragment } = render(<MyComponent />);
    
            await waitForElementToBeRemoved(screen.getByText('loading'));
    
            expect(asFragment()).toMatchSnapshot();
        })
    })
    

    I used the loading text since you mentioned it on your question. But you can also wait for your data to appear on screen:

    await screen.findByText('something that comes from the mocked data');
    

    Great job on noticing the waitFor issue and fixing it!