fix(async-utils): prevent timeout and interval checks in wait from leaving open handles #682
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What:
This issue was raised in discord but the use of
Promise.race
has also been flagged as potentially an issue with fake timers in #631.(I'm going to use "timeout" a lot in here that had slightly different meanings so I hope it doesn't get too confusing).
The timeout that get created to stop waiting after the async utils timeout is exceeded and the timeout that created for running intverval checks when the hook doesn't rerender fast enough are not being cleared when the wait condition is being satisfied and the promise resolves before they fire. This is leaving open handles which
jest
is warning about.Interestingly, the warning only appears when the
testEnvironment
is not set tojsdom
in thejest
config (like in our test suite), which I haven't been able to properly identify why, but I'm assumingjsdom
must be intercepting these handle somehow and cleaning them up, which doesn't occur when using thenode
test environment.Why:
We want to be good citizens and clean up after outselves.
How:
The
Promise.race
was not the actual cause, but the use of racing promises and letting the losing promise just run to completion was not helping here. While the implementation allowed for each part to remain relatively simple, it made it difficult to cancel the loser when the winner resolved.The new implementation introduces a
timeoutSignal
that controls the timeouts and wraps the promise in a way that is aware of when it completely as clears the pending timeouts so they are no longer left open. This means there is a little bit more ceremony in using it and we need to check the whether it timed out in a few more places to ensure things exit cleanly.Checklist:
jsdom
test environment with--detectOpenHandles
to ensure it stays working (I don't particularly want to introduce any more variations of the test suite)