How to wait until the React component completes the upgrade in Jest and / or Enzyme?

In my create-react-app, I am trying to test a component that does multiple setState when mounted.

 class MyComponent extends React.Component { state = { a: undefined, b: undefined, c: undefined, }; fetchA() { // returns a promise } fetchB() { // returns a promise } fetchC() { // returns a promise } async componentDidMount() { const a = await fetchA(); this.setState({ a }); } async componentDidUpdate(prevProps, prevState) { if (prevState.a !== this.state.a) { const [b, c] = await Promise.all([ this.fetchB(a); this.fetchC(a); ]); this.setState({ b, c }); } } ... } 

In my test, I am doing something like this, trying to end setState in componentDidUpdate before making statements.

 import { mount } from 'enzyme'; describe('MyComponent', () => { const fakeA = Promise.resolve('a'); const fakeB = Promise.resolve('b'); const fakeC = Promise.resolve('c'); MyComponent.prototype.fetchA = jest.fn(() => fakeA); MyComponent.prototype.fetchB = jest.fn(() => fakeB); MyComponent.prototype.fetchC = jest.fn(() => fakeC); it('sets needed state', async () => { const wrapper = mount(<MyComponent />); await Promise.all([ fakeA, fakeB, fakeC ]); expect(wrapper.state()).toEqual({ a: 'a', b: 'b', c: 'c', }); }); }); 

Here is the interesting part: My test above will fail because the last call to setState (in componentDidUpdate ) did not complete when this statement was made. state.a installed state.a this time, but state.b and state.c are not yet installed.

The only way I could get it to work is to insert await Promise.resolve(null) just before the statement, to give the last setState an extra tick / cycle. It looks too hacky.

Another thing I've tried is to wrap the statement in setImmediate() , which works fine as long as that statement has passed. If it fails, it will complete the entire test due to an uncaught error.

Can anyone solve this problem?

+7
asynchronous unit-testing reactjs jestjs enzyme
source share
1 answer

This is how I solved it. Hope that helps someone.

 import { mount } from 'enzyme'; describe('MyComponent', () => { const fakeA = Promise.resolve('a'); const fakeB = Promise.resolve('b'); const fakeC = Promise.resolve('c'); MyComponent.prototype.fetchA = jest.fn(() => fakeA); MyComponent.prototype.fetchB = jest.fn(() => fakeB); MyComponent.prototype.fetchC = jest.fn(() => fakeC); it('sets needed state', async (done) => { const wrapper = mount(<MyComponent />); await Promise.all([ fakeA, fakeB, fakeC ]); setImmediate(() => { // Without the try catch, failed expect will cause the // whole test to crash out. try { expect(wrapper.state()).toEqual({ a: 'a', b: 'b', c: 'c', }); } catch(error) { done.fail(error); } done(); }); }); 
+2
source share

All Articles