Controlling time when testing Javascript

Say you're writing some cool stuff in Javascript. You've got some automated tests, it makes sure the features work OK. But there's that feature relying on setTimeout and this other one relying on setInterval. Sure your testing framework handles asynchronous tests. But you'd like to avoid having slow tests because you have to wait X milliseconds for a timeout to clear. That's when Sinon.JS 'clock' (or fake timers) feature comes in and saves the day.

Sinon is a mocking Javascript library (both for Node and browsers). It allows you to create fake functions (or objects) to help checking that "this function's being called" or "this function got passed this argument". But mocking probably deserves its own article so I won't expand on it, as time is of the essence here.

ack to controlling time, then... It's done with the help of sinon.useFakeTimers() method. This will replace the implementation of setTimeout() and setInterval() so they're tied to a clock you programatically control rather than actual milliseconds.

You'd usually do the replacement during the test setup. Then, inside your tests, you'd use the clock's tick() method to move the time forward. And once you're finished, of course, you'd restore the original implementations so that other tests are not impacted. Which would result in something like:

describe('MinutesCounter', function () {

  beforeEach(function () {
    this.clock = sinon.useFakeTimers(); 
  });

  afterEach(function () {
    this.clock.restore();
  });

  it('Should be incremented once a minute has elapsed', function () {

    var counter = new MinuteCounter();
    expect(counter.count).to.equal(0);
    this.clock.tick(60000);
    expect(counter.count).to.equal(1);
  }
});

The 60 seconds it would have taken to run the test without Sinon now go by instantly. The test is faster and won't leave you waiting (too long) everytime you run it.

Not being tied to real seconds also makes the test cleaner. There's no longer need for it to be asynchronous and use setTimeout to run the assertions only after the minute has elapsed.

Sinon really helps when testing features relying on setTimeout() or setInterval(). It makes tests faster and cleaner. Definitely a valuable addition to my testing toolbelt.

comments powered by Disqus