Jasmine — Async Tests
Tags: webdev, javascript, testing, programming
Published: 2021-01-23 20:52:11

**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);
    });
  });
});
```

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);
  });
});
```

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);
});
```

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()
  });
});
```

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()
  });
});
```

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', () => { })
});
```

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');
  });
});
```

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.