Skip to content

feat!: update @sinonjs/fake-timers and support mocking Temporal#10654

Merged
sheremet-va merged 9 commits into
vitest-dev:mainfrom
hi-ogawa:fix/issue-10345
Jun 26, 2026
Merged

feat!: update @sinonjs/fake-timers and support mocking Temporal#10654
sheremet-va merged 9 commits into
vitest-dev:mainfrom
hi-ogawa:fix/issue-10345

Conversation

@hi-ogawa

@hi-ogawa hi-ogawa commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Description

Bump @sinonjs/fake-timers to 15.4.0, which adds support for mocking the Temporal API. When Temporal is present on the global object (Node.js >= 26 by default, or via a globally installed polyfill), vi.useFakeTimers() now fakes Temporal.Now alongside Date.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
  • Ideally, include a test that fails without this PR but passes with it.
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.
  • Please check Allow edits by maintainers to make review process faster. Note that this option is not available for repositories that are owned by Github organizations.

Tests

  • Run the tests with pnpm test:ci.

Documentation

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs command.

Changesets

  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.

Bump @sinonjs/fake-timers to 15.4.0, which adds support for mocking the
Temporal API. When Temporal is present on the global object (Node.js >= 26
by default, or via a globally installed polyfill), vi.useFakeTimers() now
fakes Temporal.Now alongside Date.

- regenerate the __vitest_required__ patch against 15.4.0
- document the behavior change in the v5 migration guide
- add Temporal/Intl to the documented toFake/toNotFake unions
- add a test using temporal-polyfill/global

Closes vitest-dev#10345

Co-authored-by: OpenCode (claude-opus-4-8) <[email protected]>
@netlify

netlify Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 0671e9b
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/6a3c8030f5ab0f0008eea3b3
😎 Deploy Preview https://deploy-preview-10654--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread docs/guide/migration.md

### Fake Timers Now Mock `Temporal`

Vitest now mocks the [`Temporal`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) API alongside `Date` when fake timers are enabled, following the [`@sinonjs/fake-timers` v15.4 update](https://github.com/sinonjs/fake-timers/blob/main/CHANGELOG.md#1540--2026-05-05). This only takes effect when `Temporal` is available on the global object — either natively (Node.js >= 26 by default, behind `--harmony-temporal` on older versions, and supporting browsers) or through a globally installed polyfill such as `import 'temporal-polyfill/global'`.

@hi-ogawa hi-ogawa Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@js-temporal/polyfill global installation breaks useFakeTimers and appears it's due to @js-temporal/polyfill being not fully compliant about configurable property. I'll report to there later.

issue summary

Title: Temporal.Now is non-configurable (frozen namespace) — deviates from spec, breaks reconfiguration tools

Summary
The global Temporal namespace produced by this polyfill is frozen, so Temporal.Now is non-reconfigurable. This deviates from the Temporal spec and breaks tooling that legitimately redefines Temporal.Now (e.g. @sinonjs/fake-timers ≥15.4, and therefore Vitest/Jest fake timers).

Observed descriptor

Object.getOwnPropertyDescriptor(Temporal, 'Now')
// { value: …, writable: false, enumerable: true, configurable: false }
Object.isExtensible(Temporal) // false

(Measured on @js-temporal/[email protected].)

Expected per spec
Temporal proposal §1.3.1 assigns Temporal.Now no custom attributes, so the standard built-in default applies: { writable: true, enumerable: false, configurable: true }. Two mismatches:

  • configurable should be true (this is the breaking one)
  • enumerable should be false (currently true)

For comparison, native V8 (Node ≥26) and temporal-polyfill both expose Temporal.Now as configurable: true.

Impact / repro

import '@js-temporal/polyfill'              // installs frozen Temporal globally
import { install } from '@sinonjs/fake-timers'
install()                                    // throws:
// TypeError: Cannot redefine property: Now

fake-timers builds a clock-backed Temporal by copying the namespace's own props and then Object.defineProperty(…, 'Now', …). Because the copied Now is non-configurable, the redefine throws. Any consumer that relies on the spec-guaranteed configurability hits this.

Suggested fix
Define Temporal.Now with { writable: true, enumerable: false, configurable: true } and avoid Object.freeze/non-extensible on the Temporal namespace (or at least leave Now reconfigurable), matching the spec and native engines.

Notes

  • Only affects the polyfill installed on the global object; local import { Temporal } from '@js-temporal/polyfill' is unaffected.
  • Environment: @js-temporal/[email protected], Node v24.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread docs/config/faketimers.md
## fakeTimers.toFake

- **Type:** `('setTimeout' | 'clearTimeout' | 'setImmediate' | 'clearImmediate' | 'setInterval' | 'clearInterval' | 'Date' | 'nextTick' | 'hrtime' | 'requestAnimationFrame' | 'cancelAnimationFrame' | 'requestIdleCallback' | 'cancelIdleCallback' | 'performance' | 'queueMicrotask')[]`
- **Type:** `('setTimeout' | 'clearTimeout' | 'setImmediate' | 'clearImmediate' | 'setInterval' | 'clearInterval' | 'Date' | 'nextTick' | 'hrtime' | 'requestAnimationFrame' | 'cancelAnimationFrame' | 'requestIdleCallback' | 'cancelIdleCallback' | 'performance' | 'queueMicrotask' | 'Intl' | 'Temporal')[]`

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by fix to add also Intl that has been available for some time.

hi-ogawa and others added 4 commits June 24, 2026 11:43
Seed the clock via the `now` option instead of a separate
vi.setSystemTime() call in the Temporal test and migration doc.

Co-authored-by: OpenCode (claude-opus-4-8) <[email protected]>
This reverts commit f9527e8.
@hi-ogawa
hi-ogawa marked this pull request as ready for review June 24, 2026 04:04
sheremet-va
sheremet-va previously approved these changes Jun 24, 2026
@sheremet-va

Copy link
Copy Markdown
Member

Would be nice to also support setSystemDate with a Temporal, but it's outside of the scope of this PR

@sheremet-va

Copy link
Copy Markdown
Member

Could you resolve the conflict?

hi-ogawa and others added 2 commits June 24, 2026 19:04
Bump the `sinon` catalog entry to ^22.0.0 so its `@sinonjs/fake-timers`
dependency resolves to the same patched 15.4.0 used by vitest, removing
the duplicate 15.3.2 install.

Co-authored-by: OpenCode (claude-opus-4-8) <[email protected]>
Comment thread pnpm-workspace.yaml
rollup: ^4.59.0
semver: ^7.8.3
sinon: ^21.0.3
sinon: ^22.0.0

@hi-ogawa hi-ogawa Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bumped sion to dedupe @sinonjs/fake-timers
(sinon is used just for internal test)

@hi-ogawa
hi-ogawa requested a review from sheremet-va June 25, 2026 01:10
@sheremet-va
sheremet-va merged commit f8b1532 into vitest-dev:main Jun 26, 2026
15 of 18 checks passed
@hi-ogawa
hi-ogawa deleted the fix/issue-10345 branch June 26, 2026 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Temporal.Now is not mocked when timer mocks are enabled

2 participants