How to test an async function to throw an exception in Jest
Tags: jest, javascript, unittest, webdev
Published: 2023-07-12 12:43:33

As any good developer you should always test your code.
And as any good developer you should always try to catch exception and handle errors when writing functions.

For example if you have a function like this:

```javascript
export const logName = name => {
  // do something with the name
};
```

The above  function is expecting that you always have a name defined, but this cannot be guaranteed, so what you should do is to handle the case where the name is undefined, and throw an exception in that case, and your function should look like this:

```javascript

export const funThatThrows = name => {
	if (!name) {
		throw new Error('You need the name');
	}

	// do something with name
};
```

And if you want to test the case where the function throw you an exception if no name is passed, normally what you would do it would be to write a test like this one:

```javascript
describe('funThatThrows', () => {
  it('should throw an error if name is missing', () => {
    expect(() => {
      funThatThrows();
    }).toThrow();
  });
});
```

Essentially you run your function in an anonymous function passed to the `expect`, and then you check if this throws an exception with the `toThrow` method.

### But how do you test it with functions that return promises?

Now, if you have a function that instead of being executed immediately, they must run something asynchronous, and return the value only when it's resolved, something perhaps like this:

```javascript
export const funThatThrowsAsync = async name => {
  if (!name) {
    throw new Error('You need the name');
  }
  return Promise.resolve(`hello ${name}`);
};
```

And if you try to just add `async/await` to the test we did before, something perhaps like this:

```javascript
describe('funThatThrowsAsync', () => {
  it('should throw an error if name is missing', () => {
    expect(async () => {
      await funThatThrowsAsync();
    }).toThrow();
  });
});

```

The issue with above is that instead of passing, the above will just throw the error in your shell and fail the test:

```sh
throw new Error('You need the name');
          ^
Error: You need the name
```

What you need to do to make the test to work instead, is to append the `.rejects` method before the `.toThrow()`, essentially having this formula:

```javascript
expect(function).rejects.toThrow()
```

This will tell Jest that your function is expecting to throw an error, and it will silence the error in the console.
So our test should be rewritten like this:

```javascript
describe('funThatThrowsAsync', () => {
  it('should throw an error if name is missing', () => {
    expect(async () => {
      await funThatThrowsAsync();
    }).rejects.toThrow();
  });
});
```

And now your test will pass!

```sh
 PASS  src/async/async.test.js
  Test throw with Async/Await
    funThatThrows
      ✓ should throw an error if name is missing (8 ms)
    funThatThrowsAsync
      ✓ should throw an error if name is missing (3 ms)
```

For more info you can take a look at the [official documentation](https://jestjs.io/docs/asynchronous).