3
votes

I have a react component (16.2):

import externalLibrary from 'wherever';

class MyComponent extends React.Component {
    componentDidMount() {
      externalLibrary.doStuff().then((data) => {
        this.setState({ ...this.state,
          data: data
        });
      });
    }

    render() {
        return ( 
          <div> 
            {this.state.data.map((d) => <SubComponent key={d.id}
              data={d} />)} 
          </div>
        );
    }
}

I want to unit test this (using Jest), lets say I want to write a test that checks that checks that a "SubComponent" is rendered for each item in the array "data". How can I do this? All of React's code samples for async code assume I want to test the async code, but in this case I want to test that it rendered correctly. You can assume that "externalLibrary" is mocked correctly, and we know doStuff() will resolve a data array with three items in it. How do I tell the Jest code to wait until the promise inside componentDidMount (doStuff()) resolves, then check the rendered component and count the elements?

(I'm using Enzyme too if that changes anything)

import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
import SubComponent from './SubComponent';

describe("<MyComponent />", () => {
  it("Renders the correct number of SubComponents", done => {
    wrapper = shallow(<MyComponent />);
    // This fails because it runs before the subcomponents are rendered
    expect(wrapper.find(SubComponent)).toHaveLength(3);
  });
});
1
Would this work? wrapper = await shallow(<MyComponent />); - anoop
Not like that, I can't use await in a synchronous function like the one Jest is exposing and from what I can tell (I just tried) shallow is a synchronous function (it doesn't return a promise or awaitable). Even if it did, how would it know to wait for the second render? - Arbiter

1 Answers

0
votes

This isn't answer(rather workaround), but I can't comment due to low reputation :) You can extract call to externalLibrary.doStuff() to separate method of your component's class. And then test this method regardless of componentDidMount. Calls inside componentDidMount() are guaranteed, because guys from React are doing their stuff well.

import externalLibrary from 'wherever';

class MyComponent extends React.Component {
    componentDidMount() {
      this.retrieveData();
    }

    retrieveData() {
      externalLibrary.doStuff().then((data) => {
        this.setState({ ...this.state,
          data: data
        });
      });
    }

    render() {
        return ( 
          <div> 
            {this.state.data.map((d) => <SubComponent key={d.id}
              data={d} />)} 
          </div>
        );
    }
}