DEV Community

John Au-Yeung
John Au-Yeung

Posted on • Originally published at thewebdev.info

Jasmine — Async Tests

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 Promises

We can test promises with Jasmine.

The beforeAll , afterAll , beforeEach and afterEach functions all support promises.

For instance, we can write:

describe("Using promises", function () {
  let value;

  beforeEach(function () {
    return Promise.resolve().then(function () {
      value = 0;
    });
  });

  it("should support async execution of tests", function () {
    return Promise.resolve().then(function () {
      value++;
      expect(value).toBeGreaterThan(0);
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

We called then on a promise in the beforeEach and it callbacks.

Then we can check the values in there.

It also works with the async and await syntax.

For instance, we can write:

describe("Using promises", function () {
  let value;

  beforeEach(async function () {
    await Promise.resolve()
    value = 0;
  });

  it("should support async execution of tests", async function () {
    await Promise.resolve()
    value++;
    expect(value).toBeGreaterThan(0);
  });
});
Enter fullscreen mode Exit fullscreen mode

We just rewrote the promises with the async and await syntax.

In both examples, they’ll run sequentially.

The test starts with the beforeEach callback and then run the it callback.

Changing Wait Time

The beforeEach and afterEach functions take an optional 2nd argument to set the wait until done is finished.

For example, we can write:

describe("long asynchronous specs", function () {
  beforeEach(function (done) {
    done();
  }, 1000);

  it("takes a long time", function (done) {
    setTimeout(function () {
      done();
    }, 9000);
  }, 10000);

  afterEach(function (done) {
    done();
  }, 1000);
});
Enter fullscreen mode Exit fullscreen mode

to pass in a 2nd argument with the wait time in milliseconds.

Handling Failures

Handling failures with promises can be done like any other piece of code.

If a promise is rejected in our test, then the test will fail.

For instance, if we have:

describe("promise test", function () {
  it('does a thing', function () {
    return Promise.reject()
  });
});
Enter fullscreen mode Exit fullscreen mode

then the test will fail.

With async and await , we get the same result:

describe("long asynchronous specs", function () {
  it('does a thing', async function () {
    await Promise.reject()
  });
});
Enter fullscreen mode Exit fullscreen mode

This will also fail.

We can fail a test with callbacks.

Since Jasmine 3.0, the done function can detect if an Error object is passed to the function.

If it is, then the test will fail.

For instance, we can write:

describe("long asynchronous specs", function () {
  beforeEach(function (done) {
    setTimeout(function () {
      let err;

      try {
        throw new Error()
      } catch (e) {
        err = e;
      }

      done(err);
    });
  });

  it('does something', () => { })
});
Enter fullscreen mode Exit fullscreen mode

Our beforeEach callback throw an error.

So since we call done with the err object, we’ll see that the test will fail.

Mock Clock

We can use the mock clock to avoid writing async tests.

It’ll make async code run synchronously.

For instance, we can write:

describe("long asynchronous specs", function () {
  beforeEach(function () {
    jasmine.clock().install();
  });

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

  it('does something after 10 seconds', function () {
    const callback = jasmine.createSpy('callback');
    setTimeout(function () {
      callback('foo');
    }, 10000);
    jasmine.clock().tick(10000);
    expect(callback).toHaveBeenCalledWith('foo');
  });
});
Enter fullscreen mode Exit fullscreen mode

to create a test with the mock clock.

We called jasmine.clock().install() to create the clock.

And then we run the test code by calling tick to move to the time we want.

Then when the test is done, we call jasmine.clock().uninstall() to remove the mock clock.

Conclusion

We can test various kinds of async code with Jasmine.

Promises and callbacks are all supported.

And we can make timer code synchronous with a mock clock.

Top comments (0)