Testing with Jest & async/await
Tags: javascript, testing, node, jest
Published: 2019-11-03 01:54:09

---
title: Testing with Jest & async/await
published: true
description: Testing async code in Javascript with Jest. Real useful examples!
cover_image: https://i.imgur.com/PzThp2E.png
tags: javascript, testing, node, jest
series: Testing Node.js + Mongoose with Jest
---

If you read my previous post ([Testing Node.js + Mongoose with an in-memory database](https://dev.to/paulasantamaria/testing-node-js-mongoose-with-an-in-memory-database-32np)), you know that the last couple of weeks I've been working on testing a node.js and mongoose app. 

I'm a big fan of async/await in javascript. After all, I've seen callback hell and it's not pretty. So naturally, when I started writing my tests there was a lot of **async code** that needed testing and I came across some issues that I had to figure out for my tests to work properly. 

In this post I'll share some **real examples** that'll help you test your **async javascript code using Jest**.

# Table of contents
- [Testing async functions](#testing-async-functions)
  - [Seed some data to test](#seed-some-data-to-test)
  - [*await* first and *expect* later](#await-first-and-expect-later)
  - [Use *resolves* to await the result](#use-resolves-to-await-the-result)
- [Test error handling](#test-error-handling)
  - [Test that a function doesn't throw an error](#test-that-a-function-doesnt-throw-an-error)
  - [Test that a function throws the *correct* error](#test-that-a-function-throws-the-correct-error)
- [Try it out yourself](#try-it-out-yourself)
- [More resources](#more-resources)

# Testing async functions

Here's how a test suite for async code should look like:

```js
describe('scope ', () => {
    it('works with async', async () => {
        /* Some async code testing. */
    });
});
```
Notice that the function inside `describe` is not `async`, but the one in `it` is. 

## Seed some data to test

Sometimes we need to seed our test database to have some data to work with. I'll show you two ways to achieve this:

### a. Add the data you require inside each test
Check the following code:

```js
it('should retrieve the correct product if id matches', async () => {
    // Seed.
    const createdIphone = await productModel.create(productIphone);

    // test
    const foundProduct = await productService.getById(createdIphone.id);

    expect(foundProduct.id).toBe(createdIphone.id);
    expect(foundProduct.name).toBe(productIphone.name);
});
```

The data is seeded at the beginning of the test and used later. This method is useful when we only need this particular data for this particular test. If you find yourself copy-pasting that first line in other test, consider the following method.

### b. Seed the data using *beforeEach*
Instead of adding the data in every test, simply add it inside the `beforeEach()` method like so:

```js
beforeEach(async () => await createProducts());
afterEach(async () => await dbHandler.clearDatabase());

describe('product ', () => {
    it('test that needs data', async () => {
        
    });

    it('another test that needs data', async () => {
        
    });
});
```

This way the products will be added before each test, and removed after each test, ensuring that each test has a clean start.

## *await* first and *expect* later
Since we're using `async` we can await the results of our functions and then use `expect` to verify the results, like so:

```js
it('should retrieve the correct product if id matches', async () => {
    const foundProduct = await productService.getById(productIphoneId);

    expect(foundProduct.id).toBe(productIphoneId);
    expect(foundProduct.name).toBe(productIphone.name);
});
```

## Use *resolves* to await the result

Another way of testing the results of an async function is with `resolves` which will result in Jest waiting for the async function to finish executing. 

In the following example, we wait for `getById` to resolve and then we check if the result is null:

```js
it('should return null if nothing is found', async () => {
    // mongoose.Types.ObjectId() generates a new ID that won't exist in the current database.
    await expect(productService.getById(mongoose.Types.ObjectId()))
        .resolves
        .toBeNull();
});
```

# Test error handling

## Test that a function doesn't throw an error
We can expect for an async function not to throw an error, like so:
```js
it('can be created correctly', async () => {
    expect(async () => await productService.create(productComplete))
        .not
        .toThrow();
});
```

## Test that a function throws the *correct* error
We can use `rejects` to wait for an async function to resolve with error, and then combine it with `toThrow` to make sure the error thrown is the one we expect.

```js
it('requires name and price', async () => {

    await expect(productService.create(productMissingName))
        .rejects
        .toThrow(mongoose.Error.ValidationError);

    await expect(productService.create(productMissingPrice))
        .rejects
        .toThrow(mongoose.Error.ValidationError);
});
```

# Try it out yourself

Here's a Github repo where I put together all of the examples included in this article:

{% github pawap90/test-mongoose-inmemory %}

I created this repo for my previous post, but I've improved it and included more examples for this article.

# More resources

- If you're using VSCode you might want to checkout this extension: [vscode-jest](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest)
- Also for VSCode, follow this simple recipe to debug your tests: [Debugging tests in VS Code (github.com/microsoft/vscode-recipes)](https://github.com/microsoft/vscode-recipes/tree/master/debugging-jest-tests)
- Finally, check out [Jest official documentation](https://jestjs.io/docs/en/expect)