Mock the Current Time in Tests with Temporal

To make time-dependent code testable, accept the current instant as an injected value rather than calling Temporal.Now inside the logic. Part of Getting the Current Time with Temporal.Now.

Why this scenario is tricky

Tests that read the real clock are non-deterministic: an assertion about "today" passes at noon and fails at 23:59 near a date boundary. The cure is to stop calling Temporal.Now directly in logic and instead pass the current instant in, so a test can freeze it.

Freeze time by injecting itReading Temporal.Now inside logic is untestableFreeze time by injecting itlogic calls Temporal.Nowresult depends on real clocklogic takes an instant paramtest passes a fixed oneDependency-inject the clock so 'now' is a controllable input.

Minimal working solution

import { Temporal } from '@js-temporal/polyfill';
// Accept 'now' as a parameter with a real-clock default.
function isExpired(token: { exp: Temporal.Instant }, now = Temporal.Now.instant()) {
  return Temporal.Instant.compare(now, token.exp) >= 0;
}
// Test: isExpired(tok, Temporal.Instant.from('2026-01-01T00:00:00Z'))

Now as a parameterDefault to the real clock; override in testsNow as a parameterfn(..., now=Now.instant())prod: realtest: fixed

Full production version

For larger systems, a Clock object centralizes every time read.

import { Temporal } from '@js-temporal/polyfill';
export interface Clock { now(): Temporal.Instant; }
export const systemClock: Clock = { now: () => Temporal.Now.instant() };
export const fixedClock = (i: Temporal.Instant): Clock => ({ now: () => i });
// service(deps: { clock: Clock }) => deps.clock.now()

A Clock abstractionsystemClock in prod, fixedClock in testsA Clock abstractionClock ifacesystemClockfixedClock(i)inject

Verification snippet

Determinism assertionsA fixed clock makes time-dependent tests stableAssertions that prove the edge casefixedClock(t).now()== tisExpired at t-1falseisExpired at t+1trueno real-clock readdeterministic

Common pitfalls

Clock-in-tests pitfallsGlobal monkey-patching and hidden readsWrongRightstub Date globallyleaks across testsinject a Clockscoped, explicitcall Now deep in logiccannot freezepass now as a paramcontrollable

Frequently Asked Questions

How do I freeze the current time in a unit test?

Inject the clock. Give functions a now parameter that defaults to Temporal.Now.instant(), or pass a Clock object; in tests supply a fixed instant. The logic then depends on an input you control instead of the real wall clock.

Is it better to inject a clock or stub Date globally?

Injecting a clock is safer. Global stubbing of Date or Temporal.Now can leak between tests and hides the dependency. An injected Clock makes the time dependency explicit and scoped to the code under test.