Skip to content

Commit

Permalink
feat: add runAllTimersAsync from sinonjs
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumeduboc committed Nov 9, 2022
1 parent e1de945 commit 4807e7c
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/vitest/src/integrations/mock/timers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export class FakeTimers {
this._clock.runAll()
}

async runAllAsyncTimers(): Promise<void> {
if (this._checkFakeTimers())
await this._clock.runAllAsync()
}

runOnlyPendingTimers(): void {
if (this._checkFakeTimers())
this._clock.runToLast()
Expand Down
5 changes: 5 additions & 0 deletions packages/vitest/src/integrations/vi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ class VitestUtils {
return this
}

public async runAllAsyncTimers() {
await this._timers.runAllAsyncTimers()
return this
}

public runAllTicks() {
this._timers.runAllTicks()
return this
Expand Down
106 changes: 106 additions & 0 deletions test/core/test/timers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,112 @@ describe('FakeTimers', () => {
})
})

describe('runAllAsyncTimers', () => {
it('runs all timers in order', async () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout, Promise }
const timers = new FakeTimers({ global })
timers.useFakeTimers()

const runOrder = []
const mock1 = vi.fn(() => runOrder.push('mock1'))
const mock2 = vi.fn(() => runOrder.push('mock2'))
const mock3 = vi.fn(() => runOrder.push('mock3'))
const mock4 = vi.fn(() => runOrder.push('mock4'))
const mock5 = vi.fn(() => runOrder.push('mock5'))
const mock6 = vi.fn(() => runOrder.push('mock6'))

global.setTimeout(mock1, 100)
global.setTimeout(mock2, NaN)
global.setTimeout(mock3, 0)
const intervalHandler = global.setInterval(() => {
mock4()
global.clearInterval(intervalHandler)
}, 200)
global.setTimeout(mock5, Infinity)
global.setTimeout(mock6, -Infinity)

await timers.runAllAsyncTimers()
expect(runOrder).toEqual([
'mock2',
'mock3',
'mock5',
'mock6',
'mock1',
'mock4',
])
})

it('warns when trying to advance timers while real timers are used', async () => {
const timers = new FakeTimers({
config: {
rootDir: __dirname,
},
global,
})
await expect(timers.runAllAsyncTimers()).rejects.toThrow(/Timers are not mocked/)
})

it('only runs a setTimeout callback once (ever)', async () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout, Promise }
const timers = new FakeTimers({ global })
timers.useFakeTimers()

const fn = vi.fn()
global.setTimeout(fn, 0)
expect(fn).toHaveBeenCalledTimes(0)

await timers.runAllAsyncTimers()
expect(fn).toHaveBeenCalledTimes(1)

await timers.runAllAsyncTimers()
expect(fn).toHaveBeenCalledTimes(1)
})

it('runs callbacks with arguments after the interval', async () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout, Promise }
const timers = new FakeTimers({ global })
timers.useFakeTimers()

const fn = vi.fn()
global.setTimeout(fn, 0, 'mockArg1', 'mockArg2')

await timers.runAllAsyncTimers()
expect(fn).toHaveBeenCalledTimes(1)
expect(fn).toHaveBeenCalledWith('mockArg1', 'mockArg2')
})

it('throws before allowing infinite recursion', async () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout, Promise }
const timers = new FakeTimers({ global, config: { loopLimit: 20 } })
timers.useFakeTimers()

global.setTimeout(function infinitelyRecursingCallback() {
global.setTimeout(infinitelyRecursingCallback, 0)
}, 0)

await expect(
timers.runAllAsyncTimers(),
).rejects.toThrow(
'Aborting after running 20 timers, assuming an infinite loop!',
)
})

it('also clears ticks', async () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout, Promise }
const timers = new FakeTimers({ global })
timers.useFakeTimers()

const fn = vi.fn()
global.setTimeout(() => {
process.nextTick(fn)
}, 0)
expect(fn).toHaveBeenCalledTimes(0)

await timers.runAllAsyncTimers()
expect(fn).toHaveBeenCalledTimes(1)
})
})

describe('advanceTimersByTime', () => {
it('runs timers in order', () => {
const global = { Date: FakeDate, clearTimeout, process, setTimeout }
Expand Down

0 comments on commit 4807e7c

Please sign in to comment.