My name is Mohammad Mohammad (that explains the ²). I'm from Kuwait and currently live in Los Angeles. I work at ElephantDrive as a Developer Support Engineer.I spend a lot of time playing with Node.js and open source projects on Github. Right now I'm focusing on Front End development with React/dedux. I also like building websites for fun. You can learn more about me here.

Testing Time Sensitive Operations with Jest Timer Mocks

Introduction

I mostly use Mocha testing framework with Chaijs assertion library. Lately, I've seen a lot of open source projects using Jest testing platform. I never thought about it since I've never had a problem with my current testing stack - Not untill I was trying to test time sensitive logic.

To solve this, I would use Sinon where I would use fake timers. However, I'd have to a third dependancy to my unit testing stack in addition to Mocha and chaijs. That means more configuration overhead.

Jest claims to be a zero configuration testing platform. It comes with its own assertion and mock libraries. I immediately fell in love with how easy and fast I get going with testing.

Jest provides its own fake timers and below, I describe how to use them to test time sensitive logic.

Problem

Let's say you have the following function that calls callback function x times every 1 second. How would we test it?

const everySecond = (to=5, callback, i=0) => {
  setTimeout( () => {
    if (i++ === to) {
      return;
    }
    callback();
    everySecond(to, callback, i);
  }, 1000);
}

Discussion

Let's first define our tests below:

  • Should invoke callback once after 1 second.
  • Should invoke callback three times after 3 seconds.
  • Should invoke callback a maximum of 5 times give to=5 as time goes to infinity.

Solution

Don't forget to checkout the docs on timer mocks.

here is how we'd write our tests:

jest.useFakeTimers();

test('Call callback 5 times every 1 second', () => {

  const callback = jest.fn();
  everySecond(5, callback);
  expect(callback).not.toBeCalled();

  jest.runTimersToTime(1000);                   // after 1 second
  expect(callback.mock.calls.length).toBe(1);
  jest.runTimersToTime(2999);                   // after 3 seconds
  expect(callback.mock.calls.length).toBe(3);
  jest.runTimersToTime(10000);                  // after infinity
  expect(callback.mock.calls.length).toBe(5);
});