How to successfully mock and catch an error using Jest?
Solution 1
Array.prototype.filter
is a very low-level function and mocking it to throw an error can cause your tests to not run properly.
Take this simple test:
it('should throw', () => {
expect(() => { throw new Error() }).toThrow(); // Success!
});
...which works fine...
...but mock Array.prototype.filter
to throw an error and it fails:
it('should throw', () => {
Array.prototype.filter = jest.fn(() => { throw new Error() });
expect(() => { throw new Error() }).toThrow(); // Fail!
});
Instead, just mock filter
on the array itself:
it('should throw', () => {
const user1 = { id: 1, email: '[email protected]' };
const user2 = { id: 2, email: '[email protected]' };
const userArray = [user1, user2];
const domainEnding = '.biz';
userArray.filter = () => { throw new Error() }; // <= mock filter on userArray
expect(() => { usersHelper.filterUsersByEmailDomain(userArray, domainEnding) }).toThrow(); // Success!
});
JavaScript looks for a property on the object itself before checking its prototype so the mock filter
on userArray
gets called in filterUsersByEmailDomain
and the test passes as expected.
Solution 2
You want to put your toThrow()
before the execution of the tested function, in Jest 'toX' means that it must be setup beforehand e.g: toBeCalled()
. This is why toHaveBeenCalled()
exists, as this form allows the assertion to happen after the code has run.
Related videos on Youtube
tjol
Updated on June 04, 2022Comments
-
tjol almost 2 years
I've been stuck trying to create a specific test for a few days now, and would appreciate any insight into what I may be doing wrong.
I am trying to mock out the Array filter function to throw an error.
userHelper.js
//filter users by email ending const filterUsersByEmailDomain = (usersArray, emailEnding) => { try { let bizUsers = usersArray.filter(user => { return user.email.endsWith(emailEnding); }); return bizUsers; } catch (err) { console.log('error filtering users. Throwing error.'); throw err; } }
userHelper.test.js:
it('should throw', () => { const user1 = {id: 1, email: '[email protected]'}; const user2 = {id: 2, email: '[email protected]'}; const userArray = [user1, user2]; const domainEnding = '.biz'; Array.prototype.filter = jest.fn().mockImplementation(() => {throw new Error()}); expect(() => {usersHelper.filterUsersByEmailDomain(userArray, domainEnding)}).toThrow(); });
From what I can tell, the error is being thrown, but isn't successfully being caught. I've also tried making the called to usersHelper.filterUsersByEmailDomain() within a try catch block as i have seen others do, but was also unsuccessful. Thanks in advance!
Edit: Here is the error I receive when running this test setup locally in my project.
● Testing the usersHelper module › should throw 56 | const domainEnding = '.biz'; 57 | > 58 | Array.prototype.filter = jest.fn().mockImplementation(() => {throw new Error()}); | ^ 59 | 60 | expect(() => {usersHelper.filterUsersByEmailDomain(userArray, domainEnding)}).toThrow(); 61 | }); at Array.filter.jest.fn.mockImplementation (utils/__tests__/usersHelper.test.js:58:76) at _objectSpread (node_modules/expect/build/index.js:60:46) at Object.throwingMatcher [as toThrow] (node_modules/expect/build/index.js:264:19) at Object.toThrow (utils/__tests__/usersHelper.test.js:60:87) (node:32672) UnhandledPromiseRejectionWarning: Error (node:32672) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .c atch(). (rejection id: 2) (node:32672) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
-
thopaw almost 5 yearsI would suggest that you give
spyOn
a try like inconst spy = jest.spyOn(userArray, 'filter').mockImplementation(() => throw new Error())
. jestjs.io/docs/en/jest-object#jestspyonobject-methodname -
Teneff almost 5 yearsI've setup the test repl.it/repls/MedicalIntelligentTriangles and it seems to be working fine
-
tjol almost 5 years@Teneff hmmm that is strange. The repl.it example you posted above seems to work for me as well. However, I still get an error when I run this test locally :( I have edited the post to include the error I am getting.
-
-
tjol almost 5 yearsThank you, that did the trick! Great explanation. Only thing I tweaked was the mocking of the function.
userArray.filter = jest.fn().mockImplementation(() => {throw new Error()});