Jasmine — Timer, and Async Tests

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Testing is an important part of JavaScript.

In this article, we’ll look at how to create more complex tests with Jasmine.

Testing JavaScript Timeout Functions

We can use Jasmine to test JavaScript timeout functions.

We can use the jasmine.clock() method to do this.

For instance, we can write:

describe("Manually ticking the Jasmine Clock", function () {
  let timerCallback;

  beforeEach(function () {
    timerCallback = jasmine.createSpy("timerCallback");
    jasmine.clock().install();
  });

  afterEach(function () {
    jasmine.clock().uninstall();
  });

  it("causes a timeout to be called synchronously", function () {
    setTimeout(function () {
      timerCallback();
    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();
    jasmine.clock().tick(101);
    expect(timerCallback).toHaveBeenCalled();
  });
});
Enter fullscreen mode Exit fullscreen mode

to create a timerCallback spy which we can watch.

We call jasmine.clock().install() to create the Jasmine timer.

And we call jasmine.clock().uninstall() to remove it at the end.

Then we call tick to change the time to what we want.

This way, we can check is our setTimeout callback is called.

Also, we can use it to test setInterval .

For instance, we can write:

describe("Manually ticking the Jasmine Clock", function () {
  let timerCallback;

  beforeEach(function () {
    timerCallback = jasmine.createSpy("timerCallback");
    jasmine.clock().install();
  });

  afterEach(function () {
    jasmine.clock().uninstall();
  });

  it("causes a timeout to be called synchronously", function () {
    setInterval(function () {
      timerCallback();
    }, 100);

    expect(timerCallback).not.toHaveBeenCalled();

    jasmine.clock().tick(101);
    expect(timerCallback.calls.count()).toEqual(1);

    jasmine.clock().tick(102);
    expect(timerCallback.calls.count()).toEqual(2);
  });
});
Enter fullscreen mode Exit fullscreen mode

Like with the setTimeout test, we change the clock to the time we want with the tick method.

The time is changed relative to the time that the last tick is called.

Mocking the Date

We can use the mockDate method to mock the date we want.

For instance, we can write:

describe("Manually ticking the Jasmine Clock", function () {
  let timerCallback;

  beforeEach(function () {
    timerCallback = jasmine.createSpy("timerCallback");
    jasmine.clock().install();
  });

  afterEach(function () {
    jasmine.clock().uninstall();
  });

  it("mocks time time", function () {
    const baseTime = new Date(2020, 0, 1);

    jasmine.clock().mockDate(baseTime);

    jasmine.clock().tick(50);
    expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
  });
});
Enter fullscreen mode Exit fullscreen mode

We et the baseTime to a Date instance and then use that with mockDate to set the date to when we want.

Then we call tick to move the time.

And then we used getTime to get the current time after tick is called.

Async Support

Jasmine supports testing async code.

We can test async code with:

describe("Using callbacks", function () {
  beforeEach(function (done) {
    setTimeout(function () {
      value = 0;
      done();
    }, 1);
  });

  it("supports sequential execution of async code", function (done) {
    value++;
    expect(value).toBeGreaterThan(0);
    done();
  });
});
Enter fullscreen mode Exit fullscreen mode

We have the beforeEach callback that has a setTimeout function call.

We call done in the callback so that the test code is run.

In the test code, the callback takes the done parameter to let us call done to indicate that the test is done.

To fail a test, we can use done.fail to fail the test.

For instance, we can write:

describe("Using callbacks", function () {
  var foo = function (x, callBack1, callBack2) {
    if (x) {
      setTimeout(callBack1, 0);
    } else {
      setTimeout(callBack2, 0);
    }
  };

  it("should not call the second callBack", function (done) {
    foo(true,
      done,
      function () {
        done.fail("Second callback has been called");
      }
    );
  });
});
Enter fullscreen mode Exit fullscreen mode

We called done.fail in the 2nd callback so that if it’s run, the test will fail.

Conclusion

We can run a variety of tests that has timers and async code with Jasmine.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .