-
Notifications
You must be signed in to change notification settings - Fork 222
[react-testing] do not use Promise.race to release stale act promises #2441
Conversation
e15c10e
to
d5348fc
Compare
d5348fc
to
e98fbe2
Compare
* into a set. If the result ever resolves we will remove the callback from the Set. | ||
* If it doesn't we will call all callbacks in the Set when this root is destroyed which | ||
* will unblock any stuck queues allowing subsequent tests to run | ||
* Note: This can be cleanly achieved with a `Promise.race` but that adds an extra micro-task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment about Promise.race
in case anyone would be tempted to refactor this in the future 😓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A test case that demonstrates this picky behavior that fails if you try to refactor this to use Promise.race would be a fantastic follow-up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good call, I'll see if I can put a test case together later. It's going to quite tricky to extract a minimal test case from that apollo-client
mess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been also been dealing with what can broadly be described as "apollo-client mess where task/microtask ordering is picky" too, I am full of sympathy.
// flush the micro task to wait until react commits all pending updates. | ||
await this.actPromise; | ||
await mountedPromise; | ||
this.actCallbacks.forEach((callback) => callback()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't these need to be awaited as well? And shouldn't they be invoked prior to unmounting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't these need to be awaited as well?
These callbacks will popActScope
and recursivelyFlushAsyncActWork
if needed. There's nothing to await there.
And shouldn't they be invoked prior to unmounting?
Once the root is destroyed there should be no more assertions on it, we're calling these to flush the queue out and it's not really related to this instance of the root itself. I tried moving them up but it fails the tests as it appears that the final act in the unmount
needs to be called and awaited on first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially thought "should this be prior to the unmount" too. I was thinking there'd be an uptick in "you tried to act on a component that is unmounted" console warnings but that doesn't seem to be the case, thought admittedly the sheer noisyness of web's tests makes that hard to fully confirm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic sleuthing! And a huge thanks for doing the testing in web!
A test case that fails if the code tries to be refactored to use Promise.race
would a great deterrent to stop people from speculative refactoring. That doesn't need block this PR though.
What's the relationship between this and #2438? I guess this PR superseeds that one aside from unskipping the test?
Merge when you're ready.
* into a set. If the result ever resolves we will remove the callback from the Set. | ||
* If it doesn't we will call all callbacks in the Set when this root is destroyed which | ||
* will unblock any stuck queues allowing subsequent tests to run | ||
* Note: This can be cleanly achieved with a `Promise.race` but that adds an extra micro-task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A test case that demonstrates this picky behavior that fails if you try to refactor this to use Promise.race would be a fantastic follow-up
I think I'm still going to need
To get React 17 working |
Description
Fixes an issue where using
Promise.race
in order to unblock unresolved act promises breaks functionality that rely on very specific timings asPormise.race
adds an extra tick before the act can be resolved.This was an issue with
apollo-client
and the error state ofuseLazyQuery
. After some investigation it was determined that internallyapollo-client
will set the error result twice on the internal state. With the second time being ignored due to a shallow check. The timing of when the queue gets cleared after an act changes that behaviour and causesapollo-client
to overwrite the first result.As a result this PR uses a different approach that does not add an extra tick and keeps the same timings as before which resolves the
apollo-client
useLazyQuery
issue and other "fragile" logic that depends on such timings.I have created a snapshot and ran the CI on web with all tests passing as expected along with the changes that @BPScott did for the
react-testing@v5
upgrade: https://github.com/Shopify/web/pull/75706Once we merge this we can upgrade
web
to usereact-testing@v5