Testing with React Jest and Enzyme while simulating clicks calls a function that calls a promise

  • React v15.1.0
  • Jest v12.1.1
  • Enzyme v2.3.0

I am trying to figure out how to test a component that calls a promise in a function called by a click. I was expecting the Jest runAllTicks() function to help me here, but it doesn't seem to fulfill the promise.

component:

 import React from 'react'; import Promise from 'bluebird'; function doSomethingWithAPromise() { return new Promise((resolve) => { setTimeout(() => { resolve(); }, 50); }); } export default class AsyncTest extends React.Component { constructor(props) { super(props); this.state = { promiseText: '', timeoutText: '' }; this.setTextWithPromise = this.setTextWithPromise.bind(this); this.setTextWithTimeout = this.setTextWithTimeout.bind(this); } setTextWithPromise() { return doSomethingWithAPromise() .then(() => { this.setState({ promiseText: 'there is text!' }); }); } setTextWithTimeout() { setTimeout(() => { this.setState({ timeoutText: 'there is text!' }); }, 50); } render() { return ( <div> <div id="promiseText">{this.state.promiseText}</div> <button id="promiseBtn" onClick={this.setTextWithPromise}>Promise</button> <div id="timeoutText">{this.state.timeoutText}</div> <button id="timeoutBtn" onClick={this.setTextWithTimeout}>Timeout</button> </div> ); } } 

And tests:

 import AsyncTest from '../async'; import { shallow } from 'enzyme'; import React from 'react'; jest.unmock('../async'); describe('async-test.js', () => { let wrapper; beforeEach(() => { wrapper = shallow(<AsyncTest />); }); // FAIL it('displays the promise text after click of the button', () => { wrapper.find('#promiseBtn').simulate('click'); jest.runAllTicks(); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('#promiseText').text()).toEqual('there is text!'); }); // PASS it('displays the timeout text after click of the button', () => { wrapper.find('#timeoutBtn').simulate('click'); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('#timeoutText').text()).toEqual('there is text!'); }); }); 
+5
source share
2 answers

There is not much when you need to somehow wait for the promise to be fulfilled before the end of the test. There are two main ways to do this from your code, which I see.

  • check your onClick and your promise methods onClick . Therefore, verify that onClick calls the correct function, but spies on setTextWithPromise , causing a click and claiming that setTextWithPromise been called. Then you can also get an instance of the component and call this method, which returns a promise that you can attach to the handler, and claim that it did the right thing.

  • expose a callback hint that you can convey that is called when the promise is resolved.

+1
source

I successfully solved this problem by combining the following elements:

  • Refuse the promise and immediately resolve it.
  • Use Node setImmediate to delay the test until the next tick, which will be when the promise is resolved.
  • Call Jest done to asynchronously complete the test.

In your example, it might look like this:

 global.doSomethingWithAPromise = () => Promise.resolve({}); it('displays the promise text after click of the button', (done) => { wrapper.find('#promiseBtn').simulate('click'); setImmediate( () => { expect(wrapper.find('#promiseText').text()).toEqual('there is text!'); done(); }) }); 

The update() enzyme is neither sufficient nor necessary when using this method, since Promises are never resolved in the same tick that they are created - by design. For a detailed explanation of what is happening here, see this question .

+18
source

All Articles