Skip to content

Commit

Permalink
fix(vitest): allow useFakeTimers to fake requestIdleCallback on n…
Browse files Browse the repository at this point in the history
…on browser (#5028)
  • Loading branch information
hi-ogawa committed Jan 23, 2024
1 parent 253df1c commit a9a486f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
14 changes: 10 additions & 4 deletions packages/vitest/src/integrations/mock/timers.ts
Expand Up @@ -17,6 +17,7 @@ import { isChildProcess } from '../../utils/base'
import { RealDate, mockDate, resetDate } from './date'

export class FakeTimers {
private _global: typeof globalThis
private _clock!: InstalledClock
private _fakingTime: boolean
private _fakingDate: boolean
Expand All @@ -37,6 +38,7 @@ export class FakeTimers {

this._fakingTime = false
this._fakeTimers = withGlobal(global)
this._global = global
}

clearAllTimers(): void {
Expand Down Expand Up @@ -138,13 +140,17 @@ export class FakeTimers {
if (this._userConfig?.toFake?.includes('nextTick') && isChildProcess())
throw new Error('process.nextTick cannot be mocked inside child_process')

// setImmediate/clearImmediate is not possible to mock when it's not globally avaiable and it throws an internal error.
// this might be @sinonjs/fake-timers's bug and inconsistent behavior, but for now, we silently filter out these two beforehand for browser testing.
// https://github.com/sinonjs/fake-timers/issues/277
// https://github.com/sinonjs/sinon/issues/2085
const existingFakedMethods = (this._userConfig?.toFake || toFake).filter((method) => {
switch (method) {
case 'hrtime':
case 'nextTick':
return typeof process !== 'undefined' && method in process && process[method]
case 'setImmediate':
case 'clearImmediate':
return method in this._global && this._global[method]
default:
return method in globalThis && globalThis[method]
return true
}
})

Expand Down
15 changes: 15 additions & 0 deletions test/core/test/fixtures/timers.suite.ts
Expand Up @@ -119,6 +119,21 @@ describe('FakeTimers', () => {
timers.useFakeTimers()
expect(global.clearImmediate).not.toBe(origClearImmediate)
})

it('mocks requestIdleCallback even if not on global', () => {
const global = { Date: FakeDate, clearTimeout, setTimeout };
const timers = new FakeTimers({ global, config: { toFake: ["requestIdleCallback"] }})
timers.useFakeTimers()
expect(global.requestIdleCallback).toBeDefined();
})

it('cannot mock setImmediate and clearImmediate if not on global', () => {
const global = { Date: FakeDate, clearTimeout, setTimeout };
const timers = new FakeTimers({ global, config: { toFake: ["setImmediate", "clearImmediate"] }})
timers.useFakeTimers()
expect(global.setImmediate).toBeUndefined();
expect(global.clearImmediate).toBeUndefined();
})
})

describe('runAllTicks', () => {
Expand Down

0 comments on commit a9a486f

Please sign in to comment.