Updated answer: using async
/ await
leads to cleaner code. Old code below.
I've successfully solved this problem by combining the following elements:
- Mock out the promise and make it resolve immediately
- Make the test asynchronous by marking the test function
async
- After simulating the click, wait until the next macrotask to give the promise time to resolve
In your example, that might look like this:
// Mock the promise we're testing
global.doSomethingWithAPromise = () => Promise.resolve();
// Note that our test is an async function
it('displays the promise text after click of the button', async () => {
wrapper.find('#promiseBtn').simulate('click');
await tick();
expect(wrapper.find('#promiseText').text()).toEqual('there is text!');
});
// Helper function returns a promise that resolves after all other promise mocks,
// even if they are chained like Promise.resolve().then(...)
// Technically: this is designed to resolve on the next macrotask
function tick() {
return new Promise(resolve => {
setTimeout(resolve, 0);
})
}
Enzyme's update()
is neither sufficient nor needed when using this method, because Promises never resolve in the same tick they are created -- by design. For a very detailed explanation of what is going on here, see this question.
Original answer: same logic but slightly less pretty. Use Node's setImmediate
to defer the test until the next tick, which is when the promise will resolve. Then call Jest's done
to finish the test asynchronously.
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();
})
});
This isn't as nice because you'll get big nested callbacks if you have to wait for more than one promise.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…