From 45830f580ced3ae5337af9ace4a9bd65067dfe5c Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sat, 11 Sep 2021 11:12:41 +0200 Subject: [PATCH] feat(config): Add `unstable_advanceTimersWrapper` (#1022) --- src/config.ts | 3 ++- src/wait-for.js | 13 +++++++++---- types/config.d.ts | 5 +++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/config.ts b/src/config.ts index 0f173c74..ed321155 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,7 +12,7 @@ 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). @@ -20,6 +20,7 @@ let config: InternalConfig = { // 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, diff --git a/src/wait-for.js b/src/wait-for.js index 0a1e75ed..774d8a85 100644 --- a/src/wait-for.js +++ b/src/wait-for.js @@ -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 @@ -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 @@ -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 { diff --git a/types/config.d.ts b/types/config.d.ts index c9c33633..6a3d1247 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -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 // eslint-disable-next-line @typescript-eslint/no-explicit-any