Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config): Add unstable_advanceTimersWrapper #1022

Merged
merged 10 commits into from
Sep 11, 2021
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ interface InternalConfig extends Config {
let config: InternalConfig = {
testIdAttribute: 'data-testid',
asyncUtilTimeout: 1000,
// this is to support React's async `act` function.
// asyncWrapper and advanceTimersWrapper is to support React's async `act` function.
// forcing react-testing-library to wrap all async functions would've been
// a total nightmare (consider wrapping every findBy* query and then also
// updating `within` so those would be wrapped too. Total nightmare).
// so we have this config option that's really only intended for
// react-testing-library to use. For that reason, this feature will remain
// undocumented.
asyncWrapper: cb => cb(),
unstable_advanceTimersWrapper: cb => cb(),
eventWrapper: cb => cb(),
// default value for the `hidden` option in `ByRole` queries
defaultHidden: false,
Expand Down
13 changes: 9 additions & 4 deletions src/wait-for.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function waitFor(

const usingJestFakeTimers = jestFakeTimersAreEnabled()
if (usingJestFakeTimers) {
const {unstable_advanceTimersWrapper: advanceTimersWrapper} = getConfig()
checkCallback()
// this is a dangerous rule to disable because it could lead to an
// infinite loop. However, eslint isn't smart enough to know that we're
Expand All @@ -71,7 +72,9 @@ function waitFor(
// third party code that's setting up recursive timers so rapidly that
// the user's timer's don't get a chance to resolve. So we'll advance
// by an interval instead. (We have a test for this case).
jest.advanceTimersByTime(interval)
advanceTimersWrapper(() => {
jest.advanceTimersByTime(interval)
})

// It's really important that checkCallback is run *before* we flush
// in-flight promises. To be honest, I'm not sure why, and I can't quite
Expand All @@ -84,9 +87,11 @@ function waitFor(
// of parallelization so we're fine.
// https://stackoverflow.com/a/59243586/971592
// eslint-disable-next-line no-await-in-loop
await new Promise(r => {
setTimeout(r, 0)
jest.advanceTimersByTime(0)
await advanceTimersWrapper(async () => {
await new Promise(r => {
setTimeout(r, 0)
jest.advanceTimersByTime(0)
})
})
}
} else {
Expand Down
5 changes: 5 additions & 0 deletions types/config.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export interface Config {
testIdAttribute: string
/**
* WARNING: `unstable` prefix means this API may change in patch and minor releases.
* @param cb
*/
unstable_advanceTimersWrapper(cb: (...args: unknown[]) => unknown): unknown
// eslint-disable-next-line @typescript-eslint/no-explicit-any
asyncWrapper(cb: (...args: any[]) => any): Promise<any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down