DEV Community

Alessio Michelini
Alessio Michelini

Posted on • Updated on

How to test an async function to throw an exception in Jest

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:

export const logName = name => {
  // do something with the name
};
Enter fullscreen mode Exit fullscreen mode

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:


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

    // do something with name
};
Enter fullscreen mode Exit fullscreen mode

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:

describe('funThatThrows', () => {
  it('should throw an error if name is missing', () => {
    expect(() => {
      funThatThrows();
    }).toThrow();
  });
});
Enter fullscreen mode Exit fullscreen mode

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:

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

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

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

Enter fullscreen mode Exit fullscreen mode

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

throw new Error('You need the name');
          ^
Error: You need the name
Enter fullscreen mode Exit fullscreen mode

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:

expect(function).rejects.toThrow()
Enter fullscreen mode Exit fullscreen mode

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:

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

And now your test will pass!

 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)
Enter fullscreen mode Exit fullscreen mode

For more info you can take a look at the official documentation.

Top comments (1)

Collapse
 
davidselo profile image
David Villalba Flores

Thanks for sharing, it was really useful ;)