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
};
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
};
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();
});
});
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}`);
};
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();
});
});
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
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()
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();
});
});
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)
For more info you can take a look at the official documentation.
Top comments (2)
Thank you so much! it saved a lot of time. ❤🔥
Thanks for sharing, it was really useful ;)