Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api/vi.md
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,7 @@ await vi.runOnlyPendingTimersAsync()
function setSystemTime(date: string | number | Date): Vitest
```

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.
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.

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.

Expand Down
9 changes: 9 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ Temporal.Now.instant().epochMilliseconds // 0 (was the real time in v4)
vi.useFakeTimers({ toNotFake: ['Temporal'] })
```

### `setSystemTime` Now Mocks Temporal

Previously `vi.setSystemTime` mocked only `Date` without fake timers, but now it also mocks methods of `Temporal.Now`.

```ts
vi.setSystemTime(0)
Temporal.Now.instant().epochMilliseconds // 0 (was the real time in v4)
```

### `toThrow("")` Matches Any Error Message

[`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:
Expand Down
4 changes: 3 additions & 1 deletion docs/guide/mocking.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ Don't forget that this only [mocks _external_ access](/guide/mocking/modules#moc

### Mock the current date

To mock `Date`'s time, you can use `vi.setSystemTime` helper function. This value will **not** automatically reset between different tests.
To mock `Date` and `Temporal`'s time, you can use `vi.setSystemTime` helper function. This value will **not** automatically reset between different tests.

Beware that using `vi.useFakeTimers` also changes the `Date`'s time.

Expand All @@ -180,6 +180,8 @@ const mockDate = new Date(2022, 0, 1)
vi.setSystemTime(mockDate)
const now = new Date()
expect(now.valueOf()).toBe(mockDate.valueOf())
const nowInstant = Temporal.Now.instant()
expect(nowInstant.epochMilliseconds).toBe(mockDate.valueOf())
// reset mocked time
vi.useRealTimers()
```
Expand Down
110 changes: 0 additions & 110 deletions packages/vitest/src/integrations/mock/date.ts

This file was deleted.

22 changes: 17 additions & 5 deletions packages/vitest/src/integrations/mock/timers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import type {
} from '@sinonjs/fake-timers'
import { withGlobal } from '@sinonjs/fake-timers'
import { isChildProcess } from '../../runtime/utils'
import { mockDate, RealDate, resetDate } from './date'

const RealDate = globalThis.Date

export class FakeTimers {
private _global: typeof globalThis
Expand Down Expand Up @@ -134,7 +135,7 @@ export class FakeTimers {

useRealTimers(): void {
if (this._fakingDate) {
resetDate()
this._clock.uninstall()
this._fakingDate = null
}

Expand All @@ -147,7 +148,7 @@ export class FakeTimers {
useFakeTimers(): void {
const fakeDate = this._fakingDate || Date.now()
if (this._fakingDate) {
resetDate()
this._clock.uninstall()
this._fakingDate = null
}

Expand Down Expand Up @@ -197,8 +198,19 @@ export class FakeTimers {
this._clock.setSystemTime(date)
}
else {
this._fakingDate = date ?? new Date(this.getRealSystemTime())
mockDate(this._fakingDate)
const newFakingDate = date ?? new Date(this.getRealSystemTime())
if (this._fakingDate) {
this._fakingDate = newFakingDate
this._clock.setSystemTime(newFakingDate)
}
else {
this._fakingDate = newFakingDate
this._clock = this._fakeTimers.install({
now: newFakingDate,
toFake: ['Date', 'Temporal'],
ignoreMissingTimers: true,
})
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/vitest/src/runtime/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { relative } from 'node:path'
import { Writable } from 'node:stream'
import { getSafeTimers } from '@vitest/utils/timers'
import c from 'tinyrainbow'
import { RealDate } from '../integrations/mock/date'
import { getWorkerState } from './utils'

const RealDate = globalThis.Date

export const UNKNOWN_TEST_ID = '__vitest__unknown_test__'

function getTaskIdByStack(root: string) {
Expand Down
20 changes: 20 additions & 0 deletions test/unit/test/timers-temporal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,23 @@ it('Temporal.Now follows fake timers', () => {
expect(globalThis.Temporal).toBe(real)
expect(globalThis.Temporal.Now.instant().epochMilliseconds).not.toBe(1234)
})

it('Temporal.Now follows setSystemTime without fake timers', () => {
const real = globalThis.Temporal

expect(vi.isFakeTimers()).toBe(false)
vi.setSystemTime(0)
expect(vi.isFakeTimers()).toBe(false)
expect(globalThis.Temporal).not.toBe(real)
expect(globalThis.Temporal.Now.instant().epochMilliseconds).toBe(0)

vi.setSystemTime(1234)
expect(vi.isFakeTimers()).toBe(false)
expect(globalThis.Temporal.Now.instant().epochMilliseconds).toBe(1234)

// restore
vi.useRealTimers()
expect(vi.isFakeTimers()).toBe(false)
expect(globalThis.Temporal).toBe(real)
expect(globalThis.Temporal.Now.instant().epochMilliseconds).not.toBe(1234)
})
Loading