Skip to content

Commit

Permalink
fix fakeTimer problem
Browse files Browse the repository at this point in the history
add new fakeTimer test and revise the function

add advanceTime

revise the advanceTime
  • Loading branch information
Lei Chen authored and Lei Chen committed Sep 8, 2021
1 parent 4a03704 commit 4452982
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 7 deletions.
35 changes: 35 additions & 0 deletions src/__tests__/asyncHook.fakeTimers.test.ts
Expand Up @@ -51,6 +51,41 @@ describe('async hook (fake timers) tests', () => {

expect(complete).toBe(true)
})

test('should waitFor arbitrary expectation to pass when fake timers are not advanced explicitly', async () => {
const fn = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)

const { waitFor } = renderHook(() => null)

await waitFor(() => {
expect(fn()).toBe(true)
})
})

test('should reject if timeout is passed close to when promise resolves', async () => {
const { waitFor } = renderHook(() => null)

let actual = 0
const expected = 1

setTimeout(() => {
actual = expected
}, 101)

let complete = false

await expect(
waitFor(
() => {
expect(actual).toBe(expected)
complete = true
},
{ timeout: 100, interval: 50 }
)
).rejects.toThrow(Error('Timed out in waitFor after 100ms.'))

expect(complete).toBe(false)
})
})
})

Expand Down
7 changes: 3 additions & 4 deletions src/core/asyncUtils.ts
Expand Up @@ -7,11 +7,10 @@ import {
AsyncUtils
} from '../types'

import { createTimeoutController } from '../helpers/createTimeoutController'
import { createTimeoutController, DEFAULT_TIMEOUT } from '../helpers/createTimeoutController'
import { TimeoutError } from '../helpers/error'

const DEFAULT_INTERVAL = 50
const DEFAULT_TIMEOUT = 1000

function asyncUtils(act: Act, addResolver: (callback: () => void) => void): AsyncUtils {
const wait = async (callback: () => boolean | void, { interval, timeout }: WaitOptions) => {
Expand All @@ -20,11 +19,11 @@ function asyncUtils(act: Act, addResolver: (callback: () => void) => void): Asyn
return callbackResult ?? callbackResult === undefined
}

const timeoutSignal = createTimeoutController(timeout)
const timeoutSignal = createTimeoutController(timeout, false)

const waitForResult = async () => {
while (true) {
const intervalSignal = createTimeoutController(interval)
const intervalSignal = createTimeoutController(interval, true)
timeoutSignal.onTimeout(() => intervalSignal.cancel())

await intervalSignal.wrap(new Promise<void>(addResolver))
Expand Down
21 changes: 18 additions & 3 deletions src/helpers/createTimeoutController.ts
@@ -1,9 +1,18 @@
import { WaitOptions } from '../types'
import { jestFakeTimersAreEnabled } from './jestFakeTimersAreEnabled'
const DEFAULT_TIMEOUT = 1000

function createTimeoutController(timeout: WaitOptions['timeout']) {
function createTimeoutController(
timeout: WaitOptions['timeout'] = DEFAULT_TIMEOUT,
allowFakeTimers: boolean
) {
let timeoutId: NodeJS.Timeout
const timeoutCallbacks: Array<() => void> = []

const advanceTime = async () => {
jest.advanceTimersByTime(timeout as number)
await Promise.resolve()
}
const timeoutController = {
onTimeout(callback: () => void) {
timeoutCallbacks.push(callback)
Expand All @@ -19,12 +28,18 @@ function createTimeoutController(timeout: WaitOptions['timeout']) {
timeoutCallbacks.forEach((callback) => callback())
resolve()
}, timeout)

if (jestFakeTimersAreEnabled() && allowFakeTimers) {
advanceTime()
}
}

promise
.then(resolve)
.catch(reject)
.finally(() => timeoutController.cancel())
.finally(() => {
timeoutController.cancel()
})
})
},
cancel() {
Expand All @@ -36,4 +51,4 @@ function createTimeoutController(timeout: WaitOptions['timeout']) {
return timeoutController
}

export { createTimeoutController }
export { createTimeoutController, DEFAULT_TIMEOUT }
13 changes: 13 additions & 0 deletions src/helpers/jestFakeTimersAreEnabled.ts
@@ -0,0 +1,13 @@
export const jestFakeTimersAreEnabled = () => {
/* istanbul ignore else */
if (typeof jest !== 'undefined' && jest !== null) {
return (
// legacy timers
jest.isMockFunction(setTimeout) ||
// modern timers
Object.prototype.hasOwnProperty.call(setTimeout, 'clock')
)
}
// istanbul ignore next
return false
}

0 comments on commit 4452982

Please sign in to comment.