From 4c805082321a66e8af8dcef31577211d5b74bda1 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Sun, 8 May 2022 06:45:06 +0300 Subject: [PATCH 1/2] feat: allow passing config to sinon/fake-timers --- packages/vitest/src/defaults.ts | 15 +++++++++++++++ packages/vitest/src/integrations/timers.ts | 16 ++++++++++------ packages/vitest/src/integrations/vi.ts | 22 ++++++++++++++++------ packages/vitest/src/types/config.ts | 6 ++++++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts index f0572cd6d01a..f8497232a044 100644 --- a/packages/vitest/src/defaults.ts +++ b/packages/vitest/src/defaults.ts @@ -33,6 +33,20 @@ const coverageConfigDefaults = { extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx', '.vue', '.svelte'], } as ResolvedC8Options +export const fakeTimersDefaults = { + loopLimit: 10_000, + shouldClearNativeTimers: true, + toFake: [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'setImmediate', + 'clearImmediate', + 'Date', + ], +} as NonNullable + const config = { allowOnly: !process.env.CI, watch: !process.env.CI, @@ -56,6 +70,7 @@ const config = { uiBase: '/__vitest__/', open: true, coverage: coverageConfigDefaults, + fakeTimers: fakeTimersDefaults, } export const configDefaults: Required> = Object.freeze(config) diff --git a/packages/vitest/src/integrations/timers.ts b/packages/vitest/src/integrations/timers.ts index 2e5ed102dfaa..123f19b9dd97 100644 --- a/packages/vitest/src/integrations/timers.ts +++ b/packages/vitest/src/integrations/timers.ts @@ -6,6 +6,7 @@ */ import type { + FakeTimerInstallOpts, FakeTimerWithContext, InstalledClock, } from '@sinonjs/fake-timers' @@ -19,17 +20,17 @@ export class FakeTimers { private _fakingTime: boolean private _fakingDate: boolean private _fakeTimers: FakeTimerWithContext - private _maxLoops: number + private _userConfig?: FakeTimerInstallOpts private _now = RealDate.now constructor({ global, - maxLoops = 10_000, + config, }: { global: typeof globalThis - maxLoops?: number + config: FakeTimerInstallOpts }) { - this._maxLoops = maxLoops + this._userConfig = config this._fakingDate = false @@ -104,10 +105,9 @@ export class FakeTimers { const toFake = Object.keys(this._fakeTimers.timers) as Array this._clock = this._fakeTimers.install({ - loopLimit: this._maxLoops, now: Date.now(), toFake, - shouldClearNativeTimers: true, + ...this._userConfig, }) this._fakingTime = true @@ -143,6 +143,10 @@ export class FakeTimers { return 0 } + configure(config: FakeTimerInstallOpts): void { + this._userConfig = config + } + private _checkFakeTimers() { if (!this._fakingTime) { throw new Error( diff --git a/packages/vitest/src/integrations/vi.ts b/packages/vitest/src/integrations/vi.ts index f5942488adcc..fdd6807e10e1 100644 --- a/packages/vitest/src/integrations/vi.ts +++ b/packages/vitest/src/integrations/vi.ts @@ -1,8 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' import { parseStacktrace } from '../utils/source-map' import type { VitestMocker } from '../runtime/mocker' -import { resetModules } from '../utils' +import { getWorkerState, resetModules } from '../utils' import { FakeTimers } from './timers' import type { EnhancedSpy, MaybeMocked, MaybeMockedDeep } from './spy' import { fn, isMockFunction, spies, spyOn } from './spy' @@ -13,10 +14,6 @@ class VitestUtils { private _mocker: VitestMocker constructor() { - this._timers = new FakeTimers({ - global: globalThis, - maxLoops: 10_000, - }) // @ts-expect-error injected by vite-nide this._mocker = typeof __vitest_mocker__ !== 'undefined' ? __vitest_mocker__ : null this._mockedDate = null @@ -30,11 +27,24 @@ class VitestUtils { + '\n- Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues\n' throw new Error(errorMsg) } + + const workerState = getWorkerState() + this._timers = new FakeTimers({ + global: globalThis, + config: workerState.config.fakeTimers, + }) } // timers - public useFakeTimers() { + public useFakeTimers(config?: FakeTimerInstallOpts) { + if (config) { + this._timers.configure(config) + } + else { + const workerState = getWorkerState() + this._timers.configure(workerState.config.fakeTimers) + } this._timers.useFakeTimers() return this } diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 81ce3ac78019..94ab04fcd37a 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -1,5 +1,6 @@ import type { CommonServerOptions } from 'vite' import type { PrettyFormatOptions } from 'pretty-format' +import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' import type { BuiltinReporters } from '../node/reporters' import type { C8Options, ResolvedC8Options } from './coverage' import type { JSDOMOptions } from './jsdom-options' @@ -302,6 +303,11 @@ export interface InlineConfig { * Show heap usage after each test. Usefull for debugging memory leaks. */ logHeapUsage?: boolean + + /** + * Options for @sinon/fake-timers + */ + fakeTimers?: FakeTimerInstallOpts } export interface UserConfig extends InlineConfig { From 9c597c8c335fd278d1922063a4229358757be32c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Sun, 8 May 2022 12:50:12 +0300 Subject: [PATCH 2/2] chore: fix timers test --- test/core/test/timers.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/test/timers.test.ts b/test/core/test/timers.test.ts index 24f2cc16c365..0ea12c00c635 100644 --- a/test/core/test/timers.test.ts +++ b/test/core/test/timers.test.ts @@ -176,7 +176,7 @@ describe('FakeTimers', () => { setTimeout, } - const timers = new FakeTimers({ global, maxLoops: 100 }) + const timers = new FakeTimers({ global, config: { loopLimit: 100 } }) timers.useFakeTimers() @@ -306,7 +306,7 @@ describe('FakeTimers', () => { it('throws before allowing infinite recursion', () => { const global = { Date: FakeDate, clearTimeout, process, setTimeout } - const timers = new FakeTimers({ global, maxLoops: 100 }) + const timers = new FakeTimers({ global, config: { loopLimit: 100 } }) timers.useFakeTimers() global.setTimeout(function infinitelyRecursingCallback() {