Class FakeTime

Overrides the real Date object and timer functions with fake ones that can be controlled through the fake time instance.

Note: there is no setter for the start property, as it cannot be changed after initialization.

import {
assertSpyCalls,
spy,
} from "@std/testing/mock";
import { FakeTime } from "@std/testing/time";

function secondInterval(cb: () => void): number {
return setInterval(cb, 1000);
}

Deno.test("secondInterval calls callback every second and stops after being cleared", () => {
using time = new FakeTime();

const cb = spy();
const intervalId = secondInterval(cb);
assertSpyCalls(cb, 0);
time.tick(500);
assertSpyCalls(cb, 0);
time.tick(500);
assertSpyCalls(cb, 1);
time.tick(3500);
assertSpyCalls(cb, 4);

clearInterval(intervalId);
time.tick(1000);
assertSpyCalls(cb, 4);
});

Constructors

  • Construct a FakeTime object. This overrides the real Date object and timer functions with fake ones that can be controlled through the fake time instance.

    Parameters

    • Optionalstart:
          | null
          | string
          | number
          | Date

      The time to simulate. The default is the current time.

    • Optionaloptions: FakeTimeOptions

      The options

    Returns FakeTime

    If time is already faked

    If the start is invalid

Accessors

  • get now(): number
  • The number of milliseconds elapsed since the epoch (January 1, 1970 00:00:00 UTC) for the fake time.

    Returns number

    The number of milliseconds elapsed since the epoch (January 1, 1970 00:00:00 UTC) for the fake time

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    assertEquals(fakeTime.now, 15_000);

    fakeTime.tick(5_000);

    assertEquals(fakeTime.now, 20_000);
  • set now(value): void
  • Set the current time. It will call any functions waiting to be called between the current and new fake time. If the timer callback throws, time will stop advancing forward beyond that timer.

    Parameters

    • value: number

      The current time (in milliseconds)

    Returns void

    If the time goes backwards

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    assertEquals(fakeTime.now, 15_000);

    fakeTime.now = 35_000;

    assertEquals(fakeTime.now, 35_000);
  • get start(): number
  • The initial number of milliseconds elapsed since the epoch (January 1, 1970 00:00:00 UTC) for the fake time.

    Returns number

    The initial number of milliseconds elapsed since the epoch (January 1, 1970 00:00:00 UTC) for the fake time.

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    assertEquals(fakeTime.start, 15_000);

Methods

  • Restores real time.

    Returns void

    import { FakeTime } from "@std/testing/time";
    import { assertEquals, assertNotEquals } from "@std/assert";

    const setTimeout = globalThis.setTimeout;

    {
    using fakeTime = new FakeTime();

    assertNotEquals(globalThis.setTimeout, setTimeout);

    // test timer related things.

    // You don't need to call fakeTime.restore() explicitly
    // as it's implicitly called via the [Symbol.dispose] method
    // when declared with `using`.
    }

    assertEquals(globalThis.setTimeout, setTimeout);
  • Resolves after the given number of milliseconds using real time.

    Parameters

    • ms: number

      The milliseconds to delay

    • options: DelayOptions = {}

      The options

    Returns Promise<void>

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    await fakeTime.delay(500); // wait 500 ms in real time.

    assertEquals(fakeTime.now, 15_000); // The simulated time doesn't advance.
  • Advances time to when the next scheduled timer is due. If there are no pending timers, time will not be changed.

    Returns boolean

    true when there is a scheduled timer and false when there is not.

    import { FakeTime } from "@std/testing/time";
    import { assert, assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let called = false;

    setTimeout(() => { called = true }, 5000);

    fakeTime.next();

    assert(called);
    assertEquals(fakeTime.now, 20_000);
  • Runs all pending microtasks then advances time to when the next scheduled timer is due. If there are no pending timers, time will not be changed.

    Returns Promise<boolean>

    true if the pending timers existed and the time advanced, false if there was no pending timer and the time didn't advance.

    import { FakeTime } from "@std/testing/time";
    import { assert, assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let called0 = false;
    let called1 = false;

    setTimeout(() => { called0 = true }, 5000);
    Promise.resolve().then(() => { called1 = true });

    await fakeTime.nextAsync();

    assert(called0);
    assert(called1);
    assertEquals(fakeTime.now, 20_000);
  • Restores time related global functions to their original state.

    Returns void

    import { FakeTime } from "@std/testing/time";
    import { assertEquals, assertNotEquals } from "@std/assert";

    const setTimeout = globalThis.setTimeout;

    const fakeTime = new FakeTime(); // global timers are now faked

    assertNotEquals(globalThis.setTimeout, setTimeout);

    fakeTime.restore(); // timers are restored

    assertEquals(globalThis.setTimeout, setTimeout);
  • Advances time forward to the next due timer until there are no pending timers remaining. If the timers create additional timers, they will be run too. If there is an interval, time will keep advancing forward until the interval is cleared.

    Returns void

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let count = 0;

    setTimeout(() => { count++ }, 5_000);
    setTimeout(() => { count++ }, 15_000);
    setTimeout(() => { count++ }, 35_000);

    fakeTime.runAll();

    assertEquals(count, 3);
    assertEquals(fakeTime.now, 50_000);
  • Advances time forward to the next due timer until there are no pending timers remaining. If the timers create additional timers, they will be run too. If there is an interval, time will keep advancing forward until the interval is cleared. Runs all pending microtasks before each timer.

    Returns Promise<void>

    import { FakeTime } from "@std/testing/time";
    import { assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let count = 0;

    setTimeout(() => { count++ }, 5_000);
    setTimeout(() => { count++ }, 15_000);
    setTimeout(() => { count++ }, 35_000);
    Promise.resolve().then(() => { count++ });

    await fakeTime.runAllAsync();

    assertEquals(count, 4);
    assertEquals(fakeTime.now, 50_000);
  • Runs all pending microtasks.

    Returns Promise<void>

    import { FakeTime } from "@std/testing/time";
    import { assert } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let called = false;

    Promise.resolve().then(() => { called = true });

    await fakeTime.runMicrotasks();

    assert(called);
  • Adds the specified number of milliseconds to the fake time. This will call any functions waiting to be called between the current and new fake time.

    Parameters

    • ms: number = 0

      The milliseconds to advance

    Returns void

    import {
    assertSpyCalls,
    spy,
    } from "@std/testing/mock";
    import { FakeTime } from "@std/testing/time";

    function secondInterval(cb: () => void): number {
    return setInterval(cb, 1000);
    }

    Deno.test("secondInterval calls callback every second and stops after being cleared", () => {
    using time = new FakeTime();

    const cb = spy();
    const intervalId = secondInterval(cb);
    assertSpyCalls(cb, 0);
    time.tick(500);
    assertSpyCalls(cb, 0);
    time.tick(500);
    assertSpyCalls(cb, 1);
    time.tick(3500);
    assertSpyCalls(cb, 4);

    clearInterval(intervalId);
    time.tick(1000);
    assertSpyCalls(cb, 4);
    });
  • Runs all pending microtasks then adds the specified number of milliseconds to the fake time. This will call any functions waiting to be called between the current and new fake time.

    Parameters

    • ms: number = 0

      The milliseconds to advance

    Returns Promise<void>

    import { FakeTime } from "@std/testing/time";
    import { assert, assertEquals } from "@std/assert";

    const fakeTime = new FakeTime(15_000);

    let called = false;

    Promise.resolve().then(() => { called = true });

    await fakeTime.tickAsync(5_000);

    assert(called);
    assertEquals(fakeTime.now, 20_000);
  • Restores real time.

    Returns void

    If time is already restored

    import { FakeTime } from "@std/testing/time";
    import { assertEquals, assertNotEquals } from "@std/assert"

    const setTimeout = globalThis.setTimeout;

    const fakeTime = new FakeTime();

    assertNotEquals(globalThis.setTimeout, setTimeout);

    FakeTime.restore();

    assertEquals(globalThis.setTimeout, setTimeout);
  • Restores real time temporarily until callback returns and resolves.

    Type Parameters

    • T

      The returned value type of the callback

    Parameters

    • callback: ((...args: any[]) => T | Promise<T>)

      The callback to be called while FakeTime being restored

        • (...args): T | Promise<T>
        • Parameters

          • Rest...args: any[]

          Returns T | Promise<T>

    • Rest...args: any[]

      The arguments to pass to the callback

    Returns Promise<T>

    The returned value from the callback

    If time is not faked

    import { FakeTime } from "@std/testing/time";
    import { assertEquals, assertNotEquals } from "@std/assert"

    const setTimeout = globalThis.setTimeout;

    const fakeTime = new FakeTime();

    assertNotEquals(globalThis.setTimeout, setTimeout);

    FakeTime.restoreFor(() => {
    assertEquals(globalThis.setTimeout, setTimeout);
    });