[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

feat!: enable mocking Temporal without fake timers (#10757)

Co-authored-by: Hiroshi Ogawa <4232207+hi-ogawa@users.noreply.github.com>
Co-authored-by: OpenCode <noreply@opencode.ai>

authored by

fabon
Hiroshi Ogawa
OpenCode
and committed by
GitHub
(Jul 29, 2026, 9:32 AM +0200) ac2d46b4 a1b0565c

+52 -118
+1 -1
docs/api/vi.md
··· 1159 1159 function setSystemTime(date: string | number | Date): Vitest 1160 1160 ``` 1161 1161 1162 - If fake timers are enabled, this method simulates a user changing the system clock (will affect date related API like `hrtime`, `performance.now` or `new Date()`) - however, it will not fire any timers. If fake timers are not enabled, this method will only mock `Date.*` calls. 1162 + If fake timers are enabled, this method simulates a user changing the system clock (will affect date related API like `hrtime`, `performance.now` or `new Date()`) - however, it will not fire any timers. If fake timers are not enabled, this method will only mock `Date.*` and `Temporal.Now.*` calls. 1163 1163 1164 1164 Useful if you need to test anything that depends on the current date - for example [Luxon](https://github.com/moment/luxon/) calls inside your code. 1165 1165
+9
docs/guide/migration.md
··· 201 201 vi.useFakeTimers({ toNotFake: ['Temporal'] }) 202 202 ``` 203 203 204 + ### `setSystemTime` Now Mocks Temporal 205 + 206 + Previously `vi.setSystemTime` mocked only `Date` without fake timers, but now it also mocks methods of `Temporal.Now`. 207 + 208 + ```ts 209 + vi.setSystemTime(0) 210 + Temporal.Now.instant().epochMilliseconds // 0 (was the real time in v4) 211 + ``` 212 + 204 213 ### `toThrow("")` Matches Any Error Message 205 214 206 215 [`toThrow`](/api/expect#tothrow) (and its alias `toThrowError`) treats a string argument as a substring of the error message. In Vitest 4 an empty string was special-cased to the `/^$/` pattern, so it matched only an error whose message was empty. It now behaves like any other substring, and an empty string is contained in every message:
+3 -1
docs/guide/mocking.md
··· 171 171 172 172 ### Mock the current date 173 173 174 - To mock `Date`'s time, you can use `vi.setSystemTime` helper function. This value will **not** automatically reset between different tests. 174 + To mock `Date` and `Temporal`'s time, you can use `vi.setSystemTime` helper function. This value will **not** automatically reset between different tests. 175 175 176 176 Beware that using `vi.useFakeTimers` also changes the `Date`'s time. 177 177 ··· 180 180 vi.setSystemTime(mockDate) 181 181 const now = new Date() 182 182 expect(now.valueOf()).toBe(mockDate.valueOf()) 183 + const nowInstant = Temporal.Now.instant() 184 + expect(nowInstant.epochMilliseconds).toBe(mockDate.valueOf()) 183 185 // reset mocked time 184 186 vi.useRealTimers() 185 187 ```
+20
test/unit/test/timers-temporal.test.ts
··· 24 24 expect(globalThis.Temporal).toBe(real) 25 25 expect(globalThis.Temporal.Now.instant().epochMilliseconds).not.toBe(1234) 26 26 }) 27 + 28 + it('Temporal.Now follows setSystemTime without fake timers', () => { 29 + const real = globalThis.Temporal 30 + 31 + expect(vi.isFakeTimers()).toBe(false) 32 + vi.setSystemTime(0) 33 + expect(vi.isFakeTimers()).toBe(false) 34 + expect(globalThis.Temporal).not.toBe(real) 35 + expect(globalThis.Temporal.Now.instant().epochMilliseconds).toBe(0) 36 + 37 + vi.setSystemTime(1234) 38 + expect(vi.isFakeTimers()).toBe(false) 39 + expect(globalThis.Temporal.Now.instant().epochMilliseconds).toBe(1234) 40 + 41 + // restore 42 + vi.useRealTimers() 43 + expect(vi.isFakeTimers()).toBe(false) 44 + expect(globalThis.Temporal).toBe(real) 45 + expect(globalThis.Temporal.Now.instant().epochMilliseconds).not.toBe(1234) 46 + })
+2 -1
packages/vitest/src/runtime/console.ts
··· 4 4 import { Writable } from 'node:stream' 5 5 import { getSafeTimers } from '@vitest/utils/timers' 6 6 import c from 'tinyrainbow' 7 - import { RealDate } from '../integrations/mock/date' 8 7 import { getWorkerState } from './utils' 8 + 9 + const RealDate = globalThis.Date 9 10 10 11 export const UNKNOWN_TEST_ID = '__vitest__unknown_test__' 11 12
-110
packages/vitest/src/integrations/mock/date.ts
··· 1 - /* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */ 2 - /* 3 - The MIT License (MIT) 4 - 5 - Copyright (c) 2014 Bob Lauer 6 - 7 - Permission is hereby granted, free of charge, to any person obtaining a copy 8 - of this software and associated documentation files (the "Software"), to deal 9 - in the Software without restriction, including without limitation the rights 10 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 - copies of the Software, and to permit persons to whom the Software is 12 - furnished to do so, subject to the following conditions: 13 - 14 - The above copyright notice and this permission notice shall be included in all 15 - copies or substantial portions of the Software. 16 - 17 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 - SOFTWARE. 24 - */ 25 - 26 - export const RealDate: DateConstructor = Date 27 - 28 - let now: null | number = null 29 - 30 - class MockDate extends RealDate { 31 - constructor() 32 - constructor(value: number | string) 33 - constructor( 34 - year: number, 35 - month: number, 36 - date?: number, 37 - hours?: number, 38 - minutes?: number, 39 - seconds?: number, 40 - ms?: number 41 - ) 42 - constructor( 43 - y?: number | string, 44 - m?: number, 45 - d?: number, 46 - h?: number, 47 - M?: number, 48 - s?: number, 49 - ms?: number, 50 - ) { 51 - super() 52 - 53 - let date: any 54 - switch (arguments.length) { 55 - case 0: 56 - if (now !== null) { 57 - date = new RealDate(now.valueOf()) 58 - } 59 - else { 60 - date = new RealDate() 61 - } 62 - break 63 - case 1: 64 - date = new RealDate(y!) 65 - break 66 - default: 67 - d = typeof d === 'undefined' ? 1 : d 68 - h = h || 0 69 - M = M || 0 70 - s = s || 0 71 - ms = ms || 0 72 - date = new RealDate(y as number, m!, d, h, M, s, ms) 73 - break 74 - } 75 - 76 - Object.setPrototypeOf(date, MockDate.prototype) 77 - 78 - return date 79 - } 80 - } 81 - 82 - MockDate.UTC = RealDate.UTC 83 - 84 - MockDate.now = function () { 85 - return new MockDate().valueOf() 86 - } 87 - 88 - MockDate.parse = function (dateString) { 89 - return RealDate.parse(dateString) 90 - } 91 - 92 - MockDate.toString = function () { 93 - return RealDate.toString() 94 - } 95 - 96 - export function mockDate(date: string | number | Date): void { 97 - const dateObj = new RealDate(date.valueOf()) 98 - if (Number.isNaN(dateObj.getTime())) { 99 - throw new TypeError(`mockdate: The time set is an invalid date: ${date}`) 100 - } 101 - 102 - // @ts-expect-error global 103 - globalThis.Date = MockDate 104 - 105 - now = dateObj.valueOf() 106 - } 107 - 108 - export function resetDate(): void { 109 - globalThis.Date = RealDate 110 - }
+17 -5
packages/vitest/src/integrations/mock/timers.ts
··· 13 13 } from '@sinonjs/fake-timers' 14 14 import { withGlobal } from '@sinonjs/fake-timers' 15 15 import { isChildProcess } from '../../runtime/utils' 16 - import { mockDate, RealDate, resetDate } from './date' 16 + 17 + const RealDate = globalThis.Date 17 18 18 19 export class FakeTimers { 19 20 private _global: typeof globalThis ··· 134 135 135 136 useRealTimers(): void { 136 137 if (this._fakingDate) { 137 - resetDate() 138 + this._clock.uninstall() 138 139 this._fakingDate = null 139 140 } 140 141 ··· 147 148 useFakeTimers(): void { 148 149 const fakeDate = this._fakingDate || Date.now() 149 150 if (this._fakingDate) { 150 - resetDate() 151 + this._clock.uninstall() 151 152 this._fakingDate = null 152 153 } 153 154 ··· 197 198 this._clock.setSystemTime(date) 198 199 } 199 200 else { 200 - this._fakingDate = date ?? new Date(this.getRealSystemTime()) 201 - mockDate(this._fakingDate) 201 + const newFakingDate = date ?? new Date(this.getRealSystemTime()) 202 + if (this._fakingDate) { 203 + this._fakingDate = newFakingDate 204 + this._clock.setSystemTime(newFakingDate) 205 + } 206 + else { 207 + this._fakingDate = newFakingDate 208 + this._clock = this._fakeTimers.install({ 209 + now: newFakingDate, 210 + toFake: ['Date', 'Temporal'], 211 + ignoreMissingTimers: true, 212 + }) 213 + } 202 214 } 203 215 } 204 216