Ruben
Ruben

Reputation: 326

Jest/Enzyme Class Component testing with React Suspense and React.lazy child component

So I converted an import used in a class component to React.lazy import api and wrapped it in a Suspense tag. When I test that class component, enzyme throws an error "Enzyme Internal Error: unknown node with tag 13". Is there a way to render and test the mount of the lazy loaded component rather than using shallow render?

I've already tried async await to wait until the promise of the lazy load resolved but that didn't work neither, like so:

it('async await mount', () async () => {
  const wrapper = await mount(<Component />)
}

here's example code:

Component.js

import React, { PureComponent, Suspense } from 'react'

const ChildComponent = React.lazy(() => import('../ChildComponent'))

export default class Component extends PureComponent {
  constructor() {
      super()
      this.state = {
          example: null
      }
  }

  doSomething = () => this.setState({
      example: 'example'
  })

  render() {
    return (
      <div>
        <p>Example</p>
        <Suspense fallback={<div>...loading</div>}>
            <ChildComponent 
               example={this.state.example}
               doSomething={this.doSomething}
            />
        </Suspense>
      </div>
    )
  }
}

Component.test.js

import React from 'react'
import renderer from 'react-test-renderer'
import { mount } from 'enzyme'
import Component from '../../Component'

describe('Component', () => {
    // snapshot renders loading and not children
    it('example snapshot of tree', () => {
        const tree = renderer.create(<Component />).toJSON()
        expect(tree).toMatchSnapshot()
    })

    it('example mount test', () => {
        // this test fails and throws error I state above
        const wrapper = mount(<Component />)
        wrapper.setState({ example: 'example' })
        expect(wrapper.state.example).toBe('example')
    })
})

I read that Enzyme does not support React 16.6 Suspense API yet but I wanted to know if there was still a way to test the mounted so I can use things like simulate and find API from Enzyme.

Upvotes: 18

Views: 5069

Answers (2)

ShailyAggarwal
ShailyAggarwal

Reputation: 863

I needed to test my lazy component using Enzyme. Following approach worked for me to test on component loading completion:

const myComponent = React.lazy(() => 
      import('@material-ui/icons')
      .then(module => ({ 
         default: module.KeyboardArrowRight 
      })
   )
);

Test Code ->

//mock actual component inside suspense
jest.mock("@material-ui/icons", () => { 
    return {
        KeyboardArrowRight: () => "KeyboardArrowRight",
}
});

const lazyComponent = mount(<Suspense fallback={<div>Loading...</div>}>
           {<myComponent>}
       </Suspense>);
    
const componentToTestLoaded  = await componentToTest.type._result; // to get actual component in suspense
    
expect(componentToTestLoaded.text())`.toEqual("KeyboardArrowRight");

This is hacky but working well for Enzyme library.

Upvotes: 0

pygeek
pygeek

Reputation: 7404

Solution

The GitHub issue linked by ChuckJHardy has been resolved merged and released. You are now able to use the mount API in enzyme as of 1.14.0.

References

https://github.com/airbnb/enzyme/pull/1975

Upvotes: 1

Related Questions