Fake Clock For Deterministic Timer Tests

A controllable clock that makes timer dependent logic testable without real waiting, and drives pending callbacks in exact order.

JavascriptCli Tooling

Code

export class FakeClock {
  constructor(start = 0) {
    if (!Number.isFinite(start)) throw new TypeError("start must be a finite number");
    this.now = start;
    this.timers = [];
    this.seq = 0;
  }

  setTimeout(fn, delay) {
    if (!Number.isFinite(delay) || delay <= 0) {
      throw new RangeError("delay must be a positive number");
    }
    const entry = { id: ++this.seq, due: this.now + delay, fn };
    this.timers.push(entry);
    this.timers.sort((a, b) => a.due - b.due || a.id - b.id);
    return entry.id;
  }

  clearTimeout(id) {
    this.timers = this.timers.filter((t) => t.id !== id);
  }

  advance(ms) {
    if (!Number.isFinite(ms) || ms < 0) throw new RangeError("ms must be >= 0");
    const target = this.now + ms;
    for (;;) {
      const next = this.timers[0];
      if (!next || next.due > target) break;
      this.timers.shift();
      this.now = next.due;
      next.fn();
    }
    this.now = target;
  }

  get pending() {
    return this.timers.length;
  }
}