Skip to content

Commit

Permalink
Unify advanceTimersByTime and flushPromises
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Silbermann committed Oct 3, 2023
1 parent 69b474b commit 75b76f6
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 35 deletions.
8 changes: 1 addition & 7 deletions src/__tests__/waitFor.test.js
Expand Up @@ -176,15 +176,9 @@ test('does not work after it resolves', async () => {

/** @type {import('../').FakeClock} */
const jestFakeClock = {
advanceTimersByTime: timeoutMS => {
advanceTimersByTime: async timeoutMS => {
jest.advanceTimersByTime(timeoutMS)
},
flushPromises: () => {
return new Promise(r => {
setTimeout(r, 0)
jest.advanceTimersByTime(0)
})
},
}
describe.each([
['real timers', {useTimers: () => jest.useRealTimers(), clock: undefined}],
Expand Down
15 changes: 6 additions & 9 deletions src/__tests__/waitForDOM.test.js
Expand Up @@ -65,6 +65,11 @@ function waitFor(
return error
}

/**
* @template T
* @param {() => T} cb
* @returns T
*/
function advanceTimersWrapper(cb) {
// /dom config. /react uses act() here
return cb()
Expand All @@ -78,16 +83,8 @@ function waitFor(
/** @type {import('../').FakeClock} */
const jestFakeClock = {
advanceTimersByTime: timeoutMS => {
advanceTimersWrapper(() => {
jest.advanceTimersByTime(timeoutMS)
})
},
flushPromises: () => {
return advanceTimersWrapper(async () => {
await new Promise(r => {
setTimeout(r, 0)
jest.advanceTimersByTime(0)
})
jest.advanceTimersByTime(timeoutMS)
})
},
}
Expand Down
14 changes: 4 additions & 10 deletions src/__tests__/waitForNode.js → src/__tests__/waitForNode.test.js
Expand Up @@ -37,15 +37,9 @@ function jestFakeTimersAreEnabled() {
function waitFor(callback, options) {
/** @type {import('../').FakeClock} */
const jestFakeClock = {
advanceTimersByTime: timeoutMS => {
advanceTimersByTime: async timeoutMS => {
jest.advanceTimersByTime(timeoutMS)
},
flushPromises: () => {
return new Promise(r => {
setTimeout(r, 0)
jest.advanceTimersByTime(0)
})
},
}
const clock = jestFakeTimersAreEnabled() ? jestFakeClock : undefined

Expand Down Expand Up @@ -210,15 +204,15 @@ describe('using fake modern timers', () => {
// An actual test would not have any frames pointing to this test.
expect(waitForError.stack).toMatchInlineSnapshot(`
Error: Timed out in waitFor.
at handleTimeout (<PROJECT_ROOT>/src/waitFor.ts:146:17)
at handleTimeout (<PROJECT_ROOT>/src/waitFor.ts:139:17)
at callTimer (<PROJECT_ROOT>/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js:729:24)
at doTickInner (<PROJECT_ROOT>/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js:1289:29)
at doTick (<PROJECT_ROOT>/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js:1370:20)
at Object.tick (<PROJECT_ROOT>/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js:1378:20)
at FakeTimers.advanceTimersByTime (<PROJECT_ROOT>/node_modules/@jest/fake-timers/build/modernFakeTimers.js:101:19)
at Object.advanceTimersByTime (<PROJECT_ROOT>/node_modules/jest-runtime/build/index.js:2228:26)
at Object.advanceTimersByTime (<PROJECT_ROOT>/src/__tests__/waitForNode.js:41:12)
at <PROJECT_ROOT>/src/waitFor.ts:80:15
at Object.advanceTimersByTime (<PROJECT_ROOT>/src/__tests__/waitForNode.test.js:41:12)
at <PROJECT_ROOT>/src/waitFor.ts:85:21
at new Promise (<anonymous>)
`)
})
Expand Down
11 changes: 2 additions & 9 deletions src/waitFor.ts
Expand Up @@ -7,7 +7,7 @@ function copyStackTrace(target: Error, source: Error) {
}

export interface FakeClock {
advanceTimersByTime: (timeoutMS: number) => void
advanceTimersByTime: (timeoutMS: number) => Promise<void>
flushPromises: () => Promise<void>
}

Expand Down Expand Up @@ -77,19 +77,12 @@ function waitForImpl<T>(
// waiting or when we've timed out.
// eslint-disable-next-line no-unmodified-loop-condition, @typescript-eslint/no-unnecessary-condition
while (!finished && !signal?.aborted) {
clock.advanceTimersByTime(interval)

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- No it isn't
if (finished) {
break
}

// In this rare case, we *need* to wait for in-flight promises
// to resolve before continuing. We don't need to take advantage
// of parallelization so we're fine.
// https://stackoverflow.com/a/59243586/971592
// eslint-disable-next-line no-await-in-loop
await clock.flushPromises()
await clock.advanceTimersByTime(interval)
}
}

Expand Down

0 comments on commit 75b76f6

Please sign in to comment.