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
awaitonly 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:
setImmediatefor 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
setTimeOutIf 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,awaitin 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
simulatewould 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.)