Skip to content

Commit 13b9854

Browse files
committed
feat(config): Add advanceTimersWrapper
1 parent 85f1a19 commit 13b9854

File tree

2 files changed

+26
-17
lines changed

2 files changed

+26
-17
lines changed

src/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {prettyDOM} from './pretty-dom'
44
type Callback<T> = () => T
55
interface InternalConfig extends Config {
66
_disableExpensiveErrorDiagnostics: boolean
7+
advanceTimersWrapper(cb: (...args: unknown[]) => unknown): unknown
78
}
89

910
// It would be cleaner for this to live inside './queries', but
@@ -12,14 +13,15 @@ interface InternalConfig extends Config {
1213
let config: InternalConfig = {
1314
testIdAttribute: 'data-testid',
1415
asyncUtilTimeout: 1000,
15-
// this is to support React's async `act` function.
16+
// asyncWrapper and advanceTimersWrapper is to support React's async `act` function.
1617
// forcing react-testing-library to wrap all async functions would've been
1718
// a total nightmare (consider wrapping every findBy* query and then also
1819
// updating `within` so those would be wrapped too. Total nightmare).
1920
// so we have this config option that's really only intended for
2021
// react-testing-library to use. For that reason, this feature will remain
2122
// undocumented.
2223
asyncWrapper: cb => cb(),
24+
advanceTimersWrapper: cb => cb(),
2325
eventWrapper: cb => cb(),
2426
// default value for the `hidden` option in `ByRole` queries
2527
defaultHidden: false,

src/wait-for.js

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ function waitFor(
6464

6565
const wasUsingJestFakeTimers = jestFakeTimersAreEnabled()
6666
if (wasUsingJestFakeTimers) {
67+
const {advanceTimersWrapper} = getConfig()
68+
6769
// this is a dangerous rule to disable because it could lead to an
6870
// infinite loop. However, eslint isn't smart enough to know that we're
6971
// setting finished inside `onDone` which will be called when we're done
@@ -73,26 +75,31 @@ function waitFor(
7375
try {
7476
// jest.advanceTimersByTime will not throw if
7577
ensureInvariantTimers()
78+
79+
advanceTimersWrapper(() => {
80+
// we *could* (maybe should?) use `advanceTimersToNextTimer` but it's
81+
// possible that could make this loop go on forever if someone is using
82+
// third party code that's setting up recursive timers so rapidly that
83+
// the user's timer's don't get a chance to resolve. So we'll advance
84+
// by an interval instead. (We have a test for this case).
85+
jest.advanceTimersByTime(interval)
86+
})
87+
88+
// In this rare case, we *need* to wait for in-flight promises
89+
// to resolve before continuing. We don't need to take advantage
90+
// of parallelization so we're fine.
91+
// https://stackoverflow.com/a/59243586/971592
92+
// eslint-disable-next-line no-await-in-loop
93+
await advanceTimersWrapper(async () => {
94+
await new Promise(r => {
95+
setTimeout(r, 0)
96+
jest.advanceTimersByTime(0)
97+
})
98+
})
7699
} catch (error) {
77100
reject(error)
78101
return
79102
}
80-
// we *could* (maybe should?) use `advanceTimersToNextTimer` but it's
81-
// possible that could make this loop go on forever if someone is using
82-
// third party code that's setting up recursive timers so rapidly that
83-
// the user's timer's don't get a chance to resolve. So we'll advance
84-
// by an interval instead. (We have a test for this case).
85-
jest.advanceTimersByTime(interval)
86-
87-
// In this rare case, we *need* to wait for in-flight promises
88-
// to resolve before continuing. We don't need to take advantage
89-
// of parallelization so we're fine.
90-
// https://stackoverflow.com/a/59243586/971592
91-
// eslint-disable-next-line no-await-in-loop
92-
await new Promise(r => {
93-
setTimeout(r, 0)
94-
jest.advanceTimersByTime(0)
95-
})
96103
}
97104
}
98105

0 commit comments

Comments
 (0)