diff --git a/docs/config/faketimers.md b/docs/config/faketimers.md
index 14c4544eb..fc8c4ef1c 100644
--- a/docs/config/faketimers.md
+++ b/docs/config/faketimers.md
@@ -7,7 +7,7 @@ outline: deep
- **Type:** `FakeTimerConfig`
-Options that Vitest will pass down to [`@sinon/fake-timers`](https://npmx.dev/package/@sinonjs/fake-timers) when using [`vi.useFakeTimers()`](/api/vi#vi-usefaketimers).
+Options that configure fake timers when using [`vi.useFakeTimers()`](/api/vi#vi-usefaketimers). Vitest's fake timer implementation is based on [`@sinon/fake-timers`](https://npmx.dev/package/@sinonjs/fake-timers), with additional options and behavior tailored to Vitest.
## fakeTimers.now
@@ -65,3 +65,10 @@ Relevant only when using with `shouldAdvanceTime: true`. increment mocked time b
- **Default:** `true`
Tells fake timers to clear "native" (i.e. not fake) timers by delegating to their respective handlers. When disabled, it can lead to potentially unexpected behavior if timers existed prior to starting fake timers session.
+
+## fakeTimers.fakeNodeBuiltins 5.0.0 {#faketimers-fakenodebuiltins}
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+Mock timer APIs imported from `node:timers` and `node:timers/promises`.
diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts
index 58d808c13..272aad917 100644
--- a/packages/vitest/src/defaults.ts
+++ b/packages/vitest/src/defaults.ts
@@ -1,4 +1,5 @@
-import type { CoverageOptions, ResolvedBenchmarkOptions, UserConfig } from './node/types/config'
+import type { FakeTimersConfig } from './integrations/mock/timers'
+import type { CoverageOptions, ResolvedBenchmarkOptions } from './node/types/config'
import type { FieldsWithDefaultValues } from './node/types/coverage'
import os from 'node:os'
import { isAgent, isCI } from './utils/env'
@@ -43,7 +44,7 @@ export const coverageConfigDefaults: Required = {
+const fakeTimersDefaults: FakeTimersConfig = {
loopLimit: 10_000,
shouldClearNativeTimers: true,
}
@@ -76,7 +77,7 @@ export const configDefaults: Readonly<{
include: never[]
}
coverage: CoverageOptions
- fakeTimers: import('@sinonjs/fake-timers').Config
+ fakeTimers: FakeTimersConfig
maxConcurrency: number
dangerouslyIgnoreUnhandledErrors: boolean
typecheck: {
diff --git a/packages/vitest/src/integrations/mock/timers.ts b/packages/vitest/src/integrations/mock/timers.ts
index a560f07ea..6d8bc1d7d 100644
--- a/packages/vitest/src/integrations/mock/timers.ts
+++ b/packages/vitest/src/integrations/mock/timers.ts
@@ -8,8 +8,8 @@
import type {
Clock,
FakeMethod,
- Config as FakeTimersConfig,
FakeTimers as FakeTimersContext,
+ Config as SinonFakeTimersConfig,
TemporalTimelike,
} from '@sinonjs/fake-timers'
import { withGlobal } from '@sinonjs/fake-timers'
@@ -17,6 +17,16 @@ import { isChildProcess } from '../../runtime/utils'
const RealDate = globalThis.Date
+// Custom options are implemented by patching the package
+export interface FakeTimersConfig extends SinonFakeTimersConfig {
+ /**
+ * Mock timer APIs imported from `node:timers` and `node:timers/promises`.
+ *
+ * @default false
+ */
+ fakeNodeBuiltins?: boolean
+}
+
export class FakeTimers {
private _global: typeof globalThis
private _clock!: Clock
diff --git a/packages/vitest/src/integrations/vi.ts b/packages/vitest/src/integrations/vi.ts
index 382430680..7533e9b90 100644
--- a/packages/vitest/src/integrations/vi.ts
+++ b/packages/vitest/src/integrations/vi.ts
@@ -1,4 +1,4 @@
-import type { Config as FakeTimersConfig, TemporalTimelike } from '@sinonjs/fake-timers'
+import type { TemporalTimelike } from '@sinonjs/fake-timers'
import type {
MaybeMocked,
MaybeMockedDeep,
@@ -10,6 +10,7 @@ import type { Disposable } from 'vitest/optional-runtime-types.js'
import type { RuntimeOptions, SerializedConfig } from '../runtime/config'
import type { VitestMocker } from '../runtime/moduleRunner/moduleMocker'
import type { MockFactoryWithHelper, MockOptions } from '../types/mocker'
+import type { FakeTimersConfig } from './mock/timers'
import {
clearAllMocks,
fn,
diff --git a/packages/vitest/src/node/types/config.ts b/packages/vitest/src/node/types/config.ts
index cc2d7ad2c..91deee096 100644
--- a/packages/vitest/src/node/types/config.ts
+++ b/packages/vitest/src/node/types/config.ts
@@ -1,4 +1,3 @@
-import type { Config as FakeTimersConfig } from '@sinonjs/fake-timers'
import type { PrettyFormatOptions } from '@vitest/pretty-format'
import type { SnapshotStateOptions } from '@vitest/snapshot'
import type { Arrayable } from '@vitest/utils'
@@ -12,6 +11,7 @@ import type {
UserConfig as ViteUserConfig,
} from 'vite'
import type { ChaiConfig } from '../../integrations/chai/config'
+import type { FakeTimersConfig } from '../../integrations/mock/timers'
import type { SerializedConfig } from '../../runtime/config'
import type {
SequenceHooks,
diff --git a/packages/vitest/src/public/index.ts b/packages/vitest/src/public/index.ts
index 13ad975fe..5ab028c85 100644
--- a/packages/vitest/src/public/index.ts
+++ b/packages/vitest/src/public/index.ts
@@ -31,8 +31,8 @@ export type {
} from '../api/types'
export { assert, chai, createExpect, expect, should } from '../integrations/chai'
export { inject } from '../integrations/inject'
+export type { FakeTimersConfig } from '../integrations/mock/timers'
export { Snapshots } from '../integrations/snapshot/chai'
-
export { vi, vitest } from '../integrations/vi'
export type { VitestUtils } from '../integrations/vi'
export type {
diff --git a/packages/vitest/src/runtime/config.ts b/packages/vitest/src/runtime/config.ts
index 6eb7905a1..4eafbf4c3 100644
--- a/packages/vitest/src/runtime/config.ts
+++ b/packages/vitest/src/runtime/config.ts
@@ -1,7 +1,7 @@
-import type { Config as FakeTimersConfig } from '@sinonjs/fake-timers'
import type { PrettyFormatOptions } from '@vitest/pretty-format'
import type { SnapshotEnvironment, SnapshotUpdateState } from '@vitest/snapshot'
import type { DiffOptions, SerializedDiffOptions } from '@vitest/utils/diff'
+import type { FakeTimersConfig } from '../integrations/mock/timers'
import type { LabelColor } from '../types/general'
import type {
SequenceHooks,
diff --git a/packages/vitest/src/runtime/external-executor.ts b/packages/vitest/src/runtime/external-executor.ts
index 4d5b4060d..952b37bd6 100644
--- a/packages/vitest/src/runtime/external-executor.ts
+++ b/packages/vitest/src/runtime/external-executor.ts
@@ -96,6 +96,10 @@ export class ExternalModulesExecutor {
this.resolvers = [this.vite.resolve]
}
+ public syncBuiltinESMExports(): void {
+ this.cjs.syncBuiltinESMExports()
+ }
+
async import(identifier: string): Promise