enzyme: Simulate events returning promises?
Hi there - really enjoying the library! I have a question about testing simulate
events. Many of the events in my code trigger functions that wait for promises.
onClick = async (e) => {
data = await fetchData(e.target.value)
this.setState({data})
}
In the live react, events clearly don’t return promises, but I’m not sure if enzyme’s simulate
is also event-driven. Is there a way that I can wait for a simulate event to return a promise? I know there is an alternative, but it’s a little bit more overhead.
someFunc = async () => {
data = await fetchData(e.target.value)
this.setState({data})
}
onClick = (e) => {
someFunc()
}
// test onClick calls someFunc()
// test someFunc()
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 8
- Comments: 39 (17 by maintainers)
Commits related to this issue
- FYR-6498 | Added validate and autoFocus prop to InlineEditor (#118) * FYR-6498 | Added validate and autoFocus prop to InlineEditor * FYR-6498 | Optimization - removed unnecessary prop * FYR-6498 | ... — committed to fezproof/projects by yetanotherbhai 6 years ago
- FYR-6498 | Added onCancel hook for Esc key press in InlineEditor (#129) * FYR-6498 | Added validate and autoFocus prop to InlineEditor * FYR-6498 | Updated the test cases https://github.com/airbnb/... — committed to fezproof/projects by yetanotherbhai 6 years ago
@jdgreenberger If you’ve got your fetchData mocked such that it returns an immediately resolved promise, this test approach might work for you: https://github.com/airbnb/enzyme/blob/7cd2e9a8d03d32d3518918c446906c82c68be052/test/ShallowWrapper-spec.jsx#L4181-L4188
It would rely on the fact that resolved Promise callbacks fire before the setImmediate callback. This is currently a safe assumption in v8, but less so in other JS implementations.
edit: Oops, didn’t see this was from over a month ago, sorry for the mention.
That’s how you can test async eventHandlers and stop execution of setImmediate after tests passing:
Since simulate doesn’t return a promise, the
await
only serves to delay a tick, which means you got lucky and won your race condition.This is what worked for me:
We can use async-await instead of done() callback:
setImmediate
for some reason didn’t worked for me. Not sure if what I tried is the best approach but any suggestions will help. Below is my codeReturning the value returned from the handler would be confusing? It seems like the obvious thing. I rather expected it to already do that.
To be clear: I’m not asking for Enzyme to know anything about promises or async behavior. I’m just asking for
.simulate()
to return the value returned from the handler.I have a case
testing
await Promise.resolve();
add it will pass, thank @jwbayWrap the assertion in a
setTimeOut
If you avoid simulate, and instead explicitly invoke the prop, you can do that on your own.
https://github.com/airbnb/enzyme/blob/master/src/ShallowWrapper.js#L620
this code should return a Promise, and then testing
await component.find('TouchableOpacity').simulate('press');
just a idea 😄
@Glaadiss,
wrapper.simulate("click")
does not return whatever is returned by the onClick handler. So,await
in your example is not doing anything meaningful.There still is, because you’re racing between that resolved promise, and your await.
I had some joy with async await in test functions like so:
Here httpService.getInstance returns a promise. Awaiting the wrapper update allowed the setState updates to complete.
I agree with @Peeja . It would be extremely helpful if
simulate
would return the value from the listener. The caller can then use that value however he wants, weather it’s a promise or any other value.@ljharb:
I don’t quite follow that. A single event happens once, no? You can have several clicks over time, but a single
.simulate('click')
is a one-time thing.Given that the return value of React event handlers appears to be ignored, it would be nice to be able to return a Promise which resolves when all side-effects of the event have completed, for all the use cases above. (Or, to have
.simulate()
return whatever the handler returns, which would let you return a Promise if you wanted to.)