Skip to main content
A simulated clock implementation that allows manual control over time progression. Useful for testing time-dependent behavior in state machines without waiting for real time to pass.

Class Definition

class SimulatedClock implements Clock {
  now(): number;
  setTimeout(fn: (...args: any[]) => void, timeout: number): number;
  clearTimeout(id: number): void;
  set(ms: number): void;
  increment(ms: number): void;
}

Constructor

Creates a new simulated clock instance.
const clock = new SimulatedClock();
The clock starts at time 0 and does not advance automatically.

Methods

now

Returns the current simulated time in milliseconds.
now(): number
returns
number
The current time of the simulated clock in milliseconds since the clock was created.

Example

const clock = new SimulatedClock();
console.log(clock.now()); // 0

clock.increment(1000);
console.log(clock.now()); // 1000

setTimeout

Schedules a function to be called after a specified delay.
setTimeout(fn: (...args: any[]) => void, timeout: number): number
fn
(...args: any[]) => void
required
The function to execute when the timeout expires.
timeout
number
required
The delay in milliseconds before the function should be called.
returns
number
A timeout ID that can be used with clearTimeout() to cancel the timeout.

Example

const clock = new SimulatedClock();
let called = false;

clock.setTimeout(() => {
  called = true;
}, 1000);

clock.increment(1000);
console.log(called); // true

clearTimeout

Cancels a scheduled timeout.
clearTimeout(id: number): void
id
number
required
The timeout ID returned by setTimeout().

Example

const clock = new SimulatedClock();
let called = false;

const id = clock.setTimeout(() => {
  called = true;
}, 1000);

clock.clearTimeout(id);
clock.increment(1000);
console.log(called); // false

set

Sets the clock to a specific time and executes any timeouts that should fire.
set(time: number): void
time
number
required
The new time to set the clock to, in milliseconds. Must be greater than or equal to the current time.
Throws an error if you attempt to travel back in time (set a time less than the current time).

Example

const clock = new SimulatedClock();
const calls: number[] = [];

clock.setTimeout(() => calls.push(1), 100);
clock.setTimeout(() => calls.push(2), 200);
clock.setTimeout(() => calls.push(3), 300);

clock.set(250);
console.log(calls); // [1, 2]

increment

Advances the clock by a specified amount of time and executes any timeouts that should fire.
increment(ms: number): void
ms
number
required
The amount of time in milliseconds to advance the clock.

Example

const clock = new SimulatedClock();
const calls: string[] = [];

clock.setTimeout(() => calls.push('first'), 100);
clock.setTimeout(() => calls.push('second'), 200);

clock.increment(150);
console.log(calls); // ['first']

clock.increment(100);
console.log(calls); // ['first', 'second']

Usage with XState

Testing delayed transitions

import { createMachine, createActor } from 'xstate';
import { SimulatedClock } from 'xstate/dist/SimulatedClock';

const machine = createMachine({
  initial: 'waiting',
  states: {
    waiting: {
      after: {
        1000: 'done'
      }
    },
    done: {
      type: 'final'
    }
  }
});

const clock = new SimulatedClock();
const actor = createActor(machine, { clock });

actor.start();
console.log(actor.getSnapshot().value); // 'waiting'

clock.increment(1000);
console.log(actor.getSnapshot().value); // 'done'

Testing multiple delays

import { createMachine, createActor } from 'xstate';
import { SimulatedClock } from 'xstate/dist/SimulatedClock';

const trafficLightMachine = createMachine({
  initial: 'green',
  states: {
    green: {
      after: {
        3000: 'yellow'
      }
    },
    yellow: {
      after: {
        1000: 'red'
      }
    },
    red: {
      after: {
        3000: 'green'
      }
    }
  }
});

const clock = new SimulatedClock();
const actor = createActor(trafficLightMachine, { clock });

actor.start();

console.log(actor.getSnapshot().value); // 'green'

clock.increment(3000);
console.log(actor.getSnapshot().value); // 'yellow'

clock.increment(1000);
console.log(actor.getSnapshot().value); // 'red'

clock.increment(3000);
console.log(actor.getSnapshot().value); // 'green'

Fast-forward to a specific time

import { createMachine, createActor, assign } from 'xstate';
import { SimulatedClock } from 'xstate/dist/SimulatedClock';

const counterMachine = createMachine({
  types: {} as {
    context: { count: number };
  },
  initial: 'counting',
  context: { count: 0 },
  states: {
    counting: {
      after: {
        1000: {
          actions: assign({
            count: ({ context }) => context.count + 1
          }),
          target: 'counting',
          reenter: true
        }
      }
    }
  }
});

const clock = new SimulatedClock();
const actor = createActor(counterMachine, { clock });

actor.start();

// Jump to 5 seconds
clock.set(5000);
console.log(actor.getSnapshot().context.count); // 5

Notes

Timeouts are executed in the order they were scheduled when multiple timeouts expire at the same time.
Attempting to set the clock to a time in the past will throw an error: "Unable to travel back in time".
Use SimulatedClock in tests to make time-dependent tests deterministic and fast. Instead of using setTimeout() or await new Promise(resolve => setTimeout(resolve, ms)), you can control time progression explicitly.
The simulated clock is particularly useful for testing:
  • Delayed transitions (after)
  • Timeout guards
  • Debounced actions
  • Rate limiting
  • Any time-dependent behavior