From 6c5fe49be4d80c95860878d10c07f7e917b9e60c Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 17 Jan 2024 15:37:04 +0100 Subject: [PATCH] fix(browser): don't fail when calling vi.useFakeTimers (#4992) --- .../vitest/src/integrations/mock/timers.ts | 12 +++++++++++- packages/vitest/src/utils/base.ts | 2 +- test/browser/specs/runner.test.mjs | 4 ++-- test/browser/test/timers.test.ts | 19 +++++++++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/browser/test/timers.test.ts diff --git a/packages/vitest/src/integrations/mock/timers.ts b/packages/vitest/src/integrations/mock/timers.ts index 7fc811a2b56a..77f6a35f2c22 100644 --- a/packages/vitest/src/integrations/mock/timers.ts +++ b/packages/vitest/src/integrations/mock/timers.ts @@ -138,10 +138,20 @@ export class FakeTimers { if (this._userConfig?.toFake?.includes('nextTick') && isChildProcess()) throw new Error('process.nextTick cannot be mocked inside child_process') + const existingFakedMethods = (this._userConfig?.toFake || toFake).filter((method) => { + switch (method) { + case 'hrtime': + case 'nextTick': + return typeof process !== 'undefined' && method in process && process[method] + default: + return method in globalThis && globalThis[method] + } + }) + this._clock = this._fakeTimers.install({ now: Date.now(), - toFake, ...this._userConfig, + toFake: existingFakedMethods, }) this._fakingTime = true diff --git a/packages/vitest/src/utils/base.ts b/packages/vitest/src/utils/base.ts index 3cf5cd381a82..3897cad739f7 100644 --- a/packages/vitest/src/utils/base.ts +++ b/packages/vitest/src/utils/base.ts @@ -151,7 +151,7 @@ class AggregateErrorPonyfill extends Error { export { AggregateErrorPonyfill as AggregateError } export function isChildProcess(): boolean { - return !!process?.send + return typeof process !== 'undefined' && !!process.send } export function setProcessTitle(title: string) { diff --git a/test/browser/specs/runner.test.mjs b/test/browser/specs/runner.test.mjs index eaf756e4c56f..83e169911e06 100644 --- a/test/browser/specs/runner.test.mjs +++ b/test/browser/specs/runner.test.mjs @@ -11,8 +11,8 @@ const { } = await runVitest() await test('tests are actually running', async () => { - assert.ok(browserResultJson.testResults.length === 11, 'Not all the tests have been run') - assert.ok(passedTests.length === 9, 'Some tests failed') + assert.ok(browserResultJson.testResults.length === 12, 'Not all the tests have been run') + assert.ok(passedTests.length === 10, 'Some tests failed') assert.ok(failedTests.length === 2, 'Some tests have passed but should fail') assert.doesNotMatch(stderr, /Unhandled Error/, 'doesn\'t have any unhandled errors') diff --git a/test/browser/test/timers.test.ts b/test/browser/test/timers.test.ts new file mode 100644 index 000000000000..c2e30b7d9da5 --- /dev/null +++ b/test/browser/test/timers.test.ts @@ -0,0 +1,19 @@ +import { afterEach, expect, it, vi } from 'vitest' + +afterEach(() => { + vi.useRealTimers() +}) + +it('only runs a setTimeout callback once (ever)', () => { + vi.useFakeTimers() + + const fn = vi.fn() + setTimeout(fn, 0) + expect(fn).toHaveBeenCalledTimes(0) + + vi.runAllTimers() + expect(fn).toHaveBeenCalledTimes(1) + + vi.runAllTimers() + expect(fn).toHaveBeenCalledTimes(1) +})