reactjsjestjsasynctest

Test React function components promises behaviour with Jest,


I have a React function component. I pass a function to the component as a prop, that returns a promise. I use that function on an onClick event and once the promise is resolved, I change the state of the component. Something like:

import React, { useState } from 'react';

function myComponent({ aPromiseReturningFunction }) {
    const [myState, setState] = useState('12');
    const clickHandler = () => {
      aPromiseReturningFunction().then(() => { setState('123') })
    };

    return <div onClick={ clickHandler }>{myState}</div>
}

Inside my test:

const myFunc = jest.fn(() => Promise.resolve(true));
const componentWrapper = shallow(<myComponent aPromiseReturningFunction={ myFunc }/>);
componentWrapper.simulate('click');
expect(componentWrapper.text()).toEqual('123');

Obviously the above fails, but I have not found anything that would explain how to properly test the above. Of course If I change the state outside the promise, the test passes.

Any suggestions?


Solution

  • Thanks to alextrastero, I managed to come to a solution eventually.

    What is missing from alextrastero's answer is that we should enclose the act() inside async/await like:

    import { act } from 'react-dom/test-utils'; // other testing libraries have similar methods that test async events
    
    const myFunc = jest.fn(() => Promise.resolve(true));
    
    it('updates text after onclick', async () => {
      const componentWrapper = shallow(<myComponent aPromiseReturningFunction={ myFunc }/>);
      await act(() => {
        componentWrapper.simulate('click');
      });
    
      expect(componentWrapper.text()).toEqual('123');
    });
    

    And in order for that to work, I also needed to use the regenerator-runtime/runtime package.