Last updated: Mar 7, 2024
Reading time·8 min
try/catch
try/catch
Note: if you need to test
ASYNC
code that throws, click on the following subheading:
To test an exception in Jest:
expect()
function.toThrow()
method to test the type of the thrown error.toThrow()
method to test the error message.it('tests the type of a thrown error', () => { const throwTypeError = () => { throw new TypeError('A TypeError occurred'); }; expect(throwTypeError).toThrow(TypeError); expect(throwTypeError).toThrow('A TypeError occurred'); });
The throwTypeError
function simply throws a TypeError
exception.
We passed the function directly to the expect()
function.
The first call to expect()
tests the type of the thrown exception.
expect(throwTypeError).toThrow(TypeError);
The second call tests if the message of the thrown error contains a certain string.
expect(throwTypeError).toThrow('A TypeError occurred');
You can call the toThrow()
method without passing it any arguments to test if
the function throws an error.
it('tests the type of a thrown error', () => { const throwTypeError = () => { throw new TypeError('A TypeError occurred'); }; expect(throwTypeError).toThrow(TypeError); expect(throwTypeError).toThrow('A TypeError occurred'); expect(throwTypeError).toThrow(); });
If the function you're calling takes arguments, pass an inline arrow function to
the expect()
method to supply the necessary arguments.
it('tests the type of a thrown error', () => { const throwTypeError = message => { throw new TypeError(message); }; const errorMessage = 'A TypeError occurred'; expect(() => { throwTypeError(errorMessage); }).toThrow(TypeError); expect(() => { throwTypeError(errorMessage); }).toThrow(errorMessage); expect(() => { throwTypeError(errorMessage); }).toThrow(); });
The throwTypeError()
function now takes an argument.
We have to call the expect()
function with a reference to the function that
throws and not with an error.
expect()
to provide the required argument and used the toThrow()
method like in the previous examples.If you call the expect()
function with the output of calling the
throwTypeError
function, e.g. expect(throwTypeError('test'))
, then the
throwTypeError
function would immediately throw and fail your test.
Instead, we have to pass a reference to a function to the expect()
function.
The optional argument you can pass to the toThrow()
method can be:
message
property is equal to the message
property of
the thrown errorHere are some examples.
it('tests the type of a thrown error', () => { const throwTypeError = message => { throw new TypeError(message); }; const throwTypeErrorWithMessage = () => { throwTypeError('A TypeError occurred'); }; expect(throwTypeErrorWithMessage).toThrow(/a typeerror/i); expect(throwTypeErrorWithMessage).toThrow('A TypeError'); expect(throwTypeErrorWithMessage).toThrow( /^A TypeError occurred$/i, ); expect(throwTypeErrorWithMessage).toThrow( new TypeError('A TypeError occurred'), ); expect(throwTypeErrorWithMessage).toThrow(TypeError); });
The first example uses a regular expression to check if a certain string is contained in the error message in a case-insensitive manner.
expect(throwTypeErrorWithMessage).toThrow(/a typeerror/i);
The forward slashes / /
mark the beginning and end of the regular expression.
The i
flag allows us to perform a case-insensitive search in the string.
You can remove the i
if you only want to perform a case-sensitive search.
expect(throwTypeErrorWithMessage).toThrow(/a typeerror/);
The second example tests whether a certain substring is contained in the error message.
expect(throwTypeErrorWithMessage).toThrow('A TypeError');
The next example uses a regular expression to check if the error message is equal to a specific string.
expect(throwTypeErrorWithMessage).toThrow( /^A TypeError occurred$/i, );
The caret ^
matches the beginning of the input and the dollar sign $
matches
the end of the input.
The string in the example has to be equal to the error message.
Remove the i
flag if you want to perform a case-sensitive search.
The next example checks if the supplied error matches the thrown from the function error.
expect(throwTypeErrorWithMessage).toThrow( new TypeError('A TypeError occurred'), );
The last example tests if the thrown error is of a specific type.
expect(throwTypeErrorWithMessage).toThrow(TypeError);
try/catch
try/catch
try/catch
You can also use a try/catch
statement to test an exception in Jest.
it('tests the type of a thrown error', () => { const throwTypeError = message => { throw new TypeError(message); }; // 👇️ specify how many assertions the test contains expect.assertions(3); try { throwTypeError('An error occurred'); } catch (err) { expect(err.message).toBe('An error occurred'); expect(err.message).toMatch(/an error/i); expect(err instanceof TypeError).toBe(true); } });
The except.assertions()
method call enables you to specify how many assertions
there are in the test.
If the actual number of assertions doesn't match the expected number, the test fails.
This is useful when you want to ensure that all your assertions are run.
throwTypeError
function in the try
block and the error is passed to the catch()
function.The catch()
function is where we test the caught error.
If the function you're testing doesn't throw an error, the catch()
function
would never run.
As expected, the test would still fail because you called the
expect.assertions()
method with the expected number of assertions.
You can also use the toBeInstanceOf()
and toHaveProperty
helper methods in a
similar way.
it('tests the type of a thrown error', () => { const throwTypeError = message => { throw new TypeError(message); }; // 👇️ specify how many assertions the test contains expect.assertions(2); try { throwTypeError('An error occurred'); } catch (err) { expect(err).toBeInstanceOf(TypeError); expect(err).toHaveProperty('message', 'An error occurred'); } });
The assertions test whether the caught error is an instance of TypeError
and
has a message
property that is equal to the specified string.
To test async functions that throw exceptions in Jest:
expect()
function.rejects.toThrow()
method to test the type of the thrown error and
the error message.it('tests the type of a thrown error', async () => { const throwTypeError = message => { return Promise.reject(new TypeError(message)); }; await expect(() => throwTypeError('A TypeError occurred'), ).rejects.toThrow(TypeError); await expect(() => throwTypeError('A TypeError occurred'), ).rejects.toThrow('A TypeError occurred'); });
Notice that we marked the callback function that we passed to it()
as
async.
This way, we are able to use the await
keyword to await the call to the
expect()
function.
The .rejects property is used to unwrap the reason of a rejected promise, so that another matcher can be chained.
The first assertion tests whether the function rejected a promise with a
TypeError
.
await expect(() => throwTypeError('A TypeError occurred'), ).rejects.toThrow(TypeError);
The second assertion tests whether a given substring is contained in the error message.
await expect(() => throwTypeError('A TypeError occurred'), ).rejects.toThrow('A TypeError occurred');
Make sure to use the await
keyword to await the result of calling expect()
.
Something that commonly causes issues is trying to await the async function you
pass to expect()
by mistake.
The optional argument you can pass to the toThrow()
method can be:
message
property is equal to the message
property of
the thrown errorHere are some examples.
it('tests the type of a thrown error', async () => { const throwTypeError = message => { return Promise.reject(new TypeError(message)); }; const throwTypeErrorWithMessage = () => { return throwTypeError('A TypeError occurred'); }; await expect(throwTypeErrorWithMessage).rejects.toThrow( /a typeerror/i, ); await expect(throwTypeErrorWithMessage).rejects.toThrow( 'A TypeError', ); await expect(throwTypeErrorWithMessage).rejects.toThrow( /^A TypeError occurred$/i, ); await expect(throwTypeErrorWithMessage).rejects.toThrow( new TypeError('A TypeError occurred'), ); await expect(throwTypeErrorWithMessage).rejects.toThrow( TypeError, ); });
The first example tests whether a regular expression is matched in the error message.
await expect(throwTypeErrorWithMessage).rejects.toThrow( /a typeerror/i, );
The forward slashes / /
mark the beginning and end of the regular expression.
The i
flag allows us to perform a case-insensitive search in the string.
You can remove the i
if you only want to perform a case-sensitive search.
await expect(throwTypeErrorWithMessage).rejects.toThrow( /a typeerror/, );
The second example tests whether a certain substring is contained in the error message.
await expect(throwTypeErrorWithMessage).rejects.toThrow( 'A TypeError', );
The next example uses a regular expression to check if the error message is equal to a specific string.
await expect(throwTypeErrorWithMessage).rejects.toThrow( /^A TypeError occurred$/i, );
The caret ^
matches the beginning of the input and the dollar sign $
matches
the end of the input.
The string in the example has to be equal to the error message.
Remove the i
flag if you want to perform a case-sensitive search.
The next example checks if the supplied error matches the thrown from the function error.
await expect(throwTypeErrorWithMessage).rejects.toThrow( new TypeError('A TypeError occurred'), );
The last example tests if the thrown error is of a specific type.
await expect(throwTypeErrorWithMessage).rejects.toThrow( TypeError, );
try/catch
You can also use a try/catch
statement to test async functions that throw
errors in Jest:
try
block.catch
block.it('tests the type of a thrown error', async () => { const throwTypeError = message => { return Promise.reject(new TypeError(message)); }; expect.assertions(3); try { await throwTypeError('A TypeError occurred'); } catch (err) { expect(err.message).toBe('A TypeError occurred'); expect(err.message).toMatch(/a typeerror/i); expect(err instanceof TypeError).toBe(true); } });
Notice that we used the expect.assertions()
method to specify how many
assertions the test contains.
If the expected number of assertions doesn't match the actual number, the test fails.
In our try
block, we simply call the async function that throws and await
the Promise.
The error that is thrown from the function gets passed to the catch()
function.
The catch()
function tests whether the error message matches the expectations
and whether the thrown error is an instance of TypeError
.
If the function doesn't throw an error, the catch()
function is never called
and the test fails because the expected number of assertions (3) is not equal to
the actual number of assertions (0).
You can also use the toBeInstanceOf
and toHaveProperty
helper methods.
it('tests the type of a thrown error', async () => { const throwTypeError = message => { return Promise.reject(new TypeError(message)); }; expect.assertions(2); try { await throwTypeError('A TypeError occurred'); } catch (err) { expect(err).toBeInstanceOf(TypeError); expect(err).toHaveProperty( 'message', 'A TypeError occurred', ); } });
The first assertion tests whether the thrown error is an instance of
TypeError
.
expect(err).toBeInstanceOf(TypeError);
The second example tests whether the error has a message
property that is
equal to a given string.
expect(err).toHaveProperty( 'message', 'A TypeError occurred', );
Which approach you pick is a matter of personal preference. I'd use the
await expect()
syntax from the previous subheading as I find it more concise
and just as readable.
You can learn more about the related topics by checking out the following tutorials:
process
function