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.
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'))
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()
Verification snippet
Common pitfalls
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.