Bun

interface

test.default.MockTimers

interface MockTimers

Mocking timers is a technique commonly used in software testing to simulate and control the behavior of timers, such as setInterval and setTimeout, without actually waiting for the specified time intervals.

The MockTimers API also allows for mocking of the Date constructor and setImmediate/clearImmediate functions.

The MockTracker provides a top-level timers export which is a MockTimers instance.

  • Calls ().

  • ): void;

    Enables timer mocking for the specified timers.

    Note: When you enable mocking for a specific timer, its associated clear function will also be implicitly mocked.

    Note: Mocking Date will affect the behavior of the mocked timers as they use the same internal clock.

    Example usage without setting initial time:

    import { mock } from 'node:test';
    mock.timers.enable({ apis: ['setInterval', 'Date'], now: 1234 });
    

    The above example enables mocking for the Date constructor, setInterval timer and implicitly mocks the clearInterval function. Only the Date constructor from globalThis, setInterval and clearInterval functions from node:timers, node:timers/promises, and globalThis will be mocked.

    Example usage with initial time set

    import { mock } from 'node:test';
    mock.timers.enable({ apis: ['Date'], now: 1000 });
    

    Example usage with initial Date object as time set

    import { mock } from 'node:test';
    mock.timers.enable({ apis: ['Date'], now: new Date() });
    

    Alternatively, if you call mock.timers.enable() without any parameters:

    All timers ('setInterval', 'clearInterval', 'Date', 'setImmediate', 'clearImmediate', 'setTimeout', and 'clearTimeout') will be mocked.

    The setInterval, clearInterval, setTimeout, and clearTimeout functions from node:timers, node:timers/promises, and globalThis will be mocked. The Date constructor from globalThis will be mocked.

    If there is no initial epoch set, the initial date will be based on 0 in the Unix epoch. This is January 1st, 1970, 00:00:00 UTC. You can set an initial date by passing a now property to the .enable() method. This value will be used as the initial date for the mocked Date object. It can either be a positive integer, or another Date object.

  • reset(): void;

    This function restores the default behavior of all mocks that were previously created by this MockTimers instance and disassociates the mocks from the MockTracker instance.

    Note: After each test completes, this function is called on the test context's MockTracker.

    import { mock } from 'node:test';
    mock.timers.reset();
    
  • runAll(): void;

    Triggers all pending mocked timers immediately. If the Date object is also mocked, it will also advance the Date object to the furthest timer's time.

    The example below triggers all pending timers immediately, causing them to execute without any delay.

    import assert from 'node:assert';
    import { test } from 'node:test';
    
    test('runAll functions following the given order', (context) => {
      context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
      const results = [];
      setTimeout(() => results.push(1), 9999);
    
      // Notice that if both timers have the same timeout,
      // the order of execution is guaranteed
      setTimeout(() => results.push(3), 8888);
      setTimeout(() => results.push(2), 8888);
    
      assert.deepStrictEqual(results, []);
    
      context.mock.timers.runAll();
      assert.deepStrictEqual(results, [3, 2, 1]);
      // The Date object is also advanced to the furthest timer's time
      assert.strictEqual(Date.now(), 9999);
    });
    

    Note: The runAll() function is specifically designed for triggering timers in the context of timer mocking. It does not have any effect on real-time system clocks or actual timers outside of the mocking environment.

  • time: number
    ): void;

    You can use the .setTime() method to manually move the mocked date to another time. This method only accepts a positive integer. Note: This method will execute any mocked timers that are in the past from the new time. In the below example we are setting a new time for the mocked date.

    import assert from 'node:assert';
    import { test } from 'node:test';
    test('sets the time of a date object', (context) => {
      // Optionally choose what to mock
      context.mock.timers.enable({ apis: ['Date'], now: 100 });
      assert.strictEqual(Date.now(), 100);
      // Advance in time will also advance the date
      context.mock.timers.setTime(1000);
      context.mock.timers.tick(200);
      assert.strictEqual(Date.now(), 1200);
    });
    
  • milliseconds: number
    ): void;

    Advances time for all mocked timers.

    Note: This diverges from how setTimeout in Node.js behaves and accepts only positive numbers. In Node.js, setTimeout with negative numbers is only supported for web compatibility reasons.

    The following example mocks a setTimeout function and by using .tick advances in time triggering all pending timers.

    import assert from 'node:assert';
    import { test } from 'node:test';
    
    test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
      const fn = context.mock.fn();
    
      context.mock.timers.enable({ apis: ['setTimeout'] });
    
      setTimeout(fn, 9999);
    
      assert.strictEqual(fn.mock.callCount(), 0);
    
      // Advance in time
      context.mock.timers.tick(9999);
    
      assert.strictEqual(fn.mock.callCount(), 1);
    });
    

    Alternativelly, the .tick function can be called many times

    import assert from 'node:assert';
    import { test } from 'node:test';
    
    test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
      const fn = context.mock.fn();
      context.mock.timers.enable({ apis: ['setTimeout'] });
      const nineSecs = 9000;
      setTimeout(fn, nineSecs);
    
      const twoSeconds = 3000;
      context.mock.timers.tick(twoSeconds);
      context.mock.timers.tick(twoSeconds);
      context.mock.timers.tick(twoSeconds);
    
      assert.strictEqual(fn.mock.callCount(), 1);
    });
    

    Advancing time using .tick will also advance the time for any Date object created after the mock was enabled (if Date was also set to be mocked).

    import assert from 'node:assert';
    import { test } from 'node:test';
    
    test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
      const fn = context.mock.fn();
    
      context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
      setTimeout(fn, 9999);
    
      assert.strictEqual(fn.mock.callCount(), 0);
      assert.strictEqual(Date.now(), 0);
    
      // Advance in time
      context.mock.timers.tick(9999);
      assert.strictEqual(fn.mock.callCount(), 1);
      assert.strictEqual(Date.now(), 9999);
    });