Clock

Test trials, expiries and schedules without waiting, by moving the device's wall clock forward, to an instant or freezing it from a spec or a suite.

device.clock moves the wall clock the app reads with Date.now(), so a 14-day trial can expire in one step. The real time comes back when the test ends.

await device.clock.advance("15d");
await device.clock.set("2027-01-01T00:00:00Z", { frozen: true }); // iOS only
await device.clock.during("2027-01-01T00:00:00Z", async () => { /* ... */ });
await device.clock.reset();
CallDoes
advance(duration)move the clock forward from now
set(instant, { frozen? })jump to an ISO instant; frozen holds it there (iOS only)
during(instant, fn)run fn at that instant, then restore
reset()back to the suite's conditions.clock, or real time without one

Durations are milliseconds or "10s", "2m", "2d". The wall clock moves; monotonic clocks do not, so timers and animations keep running. On iOS the clock changes only for an app launched with the network dylib, as for the network.

Practice

  • A large offset breaks TLS: certificates look expired or not yet valid, so HTTPS fails while the clock is far from real time. Do not make requests in a spec that advances the clock by weeks.
  • A JS timer armed while the clock was ahead waits for the shifted time once the clock goes back. Re-read the time on demand (the example's clock card has a Refresh button) or relaunch the app after reset().

In a suite

warden.config.ts
conditions: { clock: { offset: "2d" } },

clock takes an ISO instant (it keeps running), { at, frozen? } or { offset: "2d" }. On iOS, declaring it launches every app with the dylib.

Per-platform behaviour and warden ui clock: Clock on a simulator.

On this page