Testing async componentDidMount() with react-test-renderer

Viewed 882

I have a component which does some SQLite loads in it's componentDidMount() function

async componentDidMount() {
    try {
        const user = await this.userDao.getUserData();
        const setupNeeded = user === null;
        if( setupNeeded ) {
            this.setState({
                status : 'setup'
            });
        }
        else {
            this.setState({
                status : 'ready',
                seed: user.seed
            })
        }
    } catch (e) {
        logger.error("Error during db query", e);
        this.setState({
            status: 'corrupted'
        });
    }
}

And I would like to test the rendered result after the call to getUserData() has been resolved, and the state has been set accordingly. Now in my test, I have the actual call to the database mocked away, so the Promise should be resolved immediately, yet testing like this does not work as expected:

Initially, I tried it like this:

test('Should render SetNewPasswordScreen', async () => {
    const tree = await renderer.create(<IndexScreen/>);
    const json = tree.toJSON();
    // expect stuff
});

However the json in this case contains the data of the initial render() call.`

Doing it like this will work:

 test('Should render SetNewPasswordScreen', (done) => {
     const tree = renderer.create(<IndexScreen/>);
     setTimeout(() => {
         const json = tree.toJSON();
         // expect stuff
     }, 5000);
 });

But this is not ideal, because I am just guessing that after 5 seconds everything will be done, but I don't know. Also, it's less then suitable if a test takes 5 seconds to finish. (I used 5 seconds arbitrarily, probably it will also work with much less since the async call is mocked anyway, but I can never really know)

My question is if anybody has a better idea of how to solve this issue?

2 Answers
it('should render setNewPassWordScreen', async () => {
   const tree = await renderer.create(<IndexScreen/>);
   const instance = tree.getInstance();

   await instance.componentDidMount();
   // expect other stuff.
});

you could use the wait for expect package: https://www.npmjs.com/package/wait-for-expect

test('Should render SetNewPasswordScreen', async (done) => {
     const tree = renderer.create(<IndexScreen/>);

     await waitForExpect(() => {
       const json = tree.toJSON();
       // expect stuff
     });
 });

mind the function passed into the test('...', fn) is now an async function.

Related