javascriptreactjsunit-testingjestjsreact-test-renderer

How to test snapshots with Jest and new React lazy 16.6 API


I have to components imported with the new React lazy API (16.6).

import React, {PureComponent, lazy} from 'react';

const Component1 = lazy(() => import('./Component1'));
const Component2 = lazy(() => import('./Component2'));

class CustomComponent extends PureComponent {
  ...
  render() {

  return (
    <div>
      <Component1 />
      <Component2 />
    </div>
  );
 }
}

In my tests, I'm doing the snapshots of this component. It's a very straightforward test:

import { create } from 'react-test-renderer';

const tree = await create(<CustomComponent />).toJSON();

expect(tree).toMatchSnapshot();

In the logs, the test is failing with this error:

A React component suspended while rendering, but no fallback UI was specified.

Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.

Do I have to wrap in every single test suite with <Suspense>...?

it('should show the component', async () => {
  const component = await create(
    <React.Suspense fallback={<div>loading</div>}>
     <CustomComponent /> 
    </React.Suspense> 
  ); 
  const tree = component.toJSON(); 

  expect(tree).toMatchSnapshot(); 

};

If I do that, I only see in the snapshot the fallback component.

+ Array [ + <div> + loading + </div>, + ]

So, which is the best way to do it?


Solution

  • Do I have to wrap in every single test suite with <Suspense>?

    Yes, the Suspense component is neccessary for lazily loading child components, particularly providing a fallback and for reconciliation when the lazy components are available.

    Export Component1 and Component2 in CustomComponent so that they can be imported in tests.

    import React, {PureComponent, lazy} from 'react';
    
    export const Component1 = lazy(() => import('./Component1'));
    export const Component2 = lazy(() => import('./Component2'));
    
    export default class CustomComponent extends PureComponent {
      //...
    }
    

    Remember that the lazy loaded components are promise-like. Import them in the test, and wait for them to resolve before doing a check that the snapshot matches.

    import { create } from 'react-test-renderer';
    import React, {Suspense} from 'react';
    import CustomComponent, {Component1, Component2} from './LazyComponent';
    
    describe('CustomComponent', () => {
      it('rendered lazily', async()=> {
        const root = create(
          <Suspense fallback={<div>loading...</div>}>
            <CustomComponent/>
          </Suspense>
        );
    
        await Component1;
        await Component2;
        expect(root).toMatchSnapshot();
      })
    })