DEV Community

Discussion on: The only 3 steps you need to mock an API call in Jest

Collapse
 
zaklaughton profile image
Zak Laughton • Edited

I think I see what you're saying: Returning undefined in a mocked endpoint is ambiguous, and it would be nice to instead return an error that clearly says "This endpoint/mock is not defined". I hadn't thought about before. Great idea!

Doing some research, I can't find a built-in Jest method to automatically make all function calls in a module fail, but you can create a manual mock file that will return an error for all functions using .mockImplementation():

// __mocks__/axios.js
const axios = jest.genMockFromModule('axios');

const throwUnmockedError = () => {
  throw new Error(`This endpoint has been mocked, but hasn't been given a manual response`);
};

// Make all axios methods return the unmocked error
// List of axios methods taken from README at https://github.com/axios/axios
axios.post.mockImplementation(throwUnmockedError);
axios.request.mockImplementation(throwUnmockedError);
axios.get.mockImplementation(throwUnmockedError);
axios.delete.mockImplementation(throwUnmockedError);
axios.head.mockImplementation(throwUnmockedError);
axios.options.mockImplementation(throwUnmockedError);
axios.post.mockImplementation(throwUnmockedError);
axios.put.mockImplementation(throwUnmockedError);
axios.patch.mockImplementation(throwUnmockedError);

module.exports = axios;
Enter fullscreen mode Exit fullscreen mode

Then, when you try to call a mocked function without a user-defined mock, the error will look something like this:

Jest unmocked output error screenshot

I created a branch on the demo repository that uses this strategy: mock-with-failed-requests. If you clone the repo, switch to that branch, and run npm run test:mocked, you'll get the error in the screenshot above.

If you play around with it a bit, there might also be a way to more clearly show exactly which mocked function triggered the error. You could also create a function to map through all the methods, which would clean up the manual mock and automatically include any additional methods added in the future.

I hope this helps!

Collapse
 
jikuja profile image
Janne Kujanpää

Throwing an exception is one solution butcode under test might catch exceptions but I have not found any nice way to do something simple like fail().

Looks like there has been plans for fail(<message>) in jest-extended(1) but is it still unimplemented.

(1) npmjs.com/package/jest-extended#fa...

Looks like:

const throwUnmockedError = () => {
  expect(0).toEqual(1)
};

does the trick but is not really pretty and I'm sure that there are use cases when that approach just will not work.

Thread Thread
 
zaklaughton profile image
Zak Laughton

Oh you're right! There's not a great way to fail a test from an imported module when the tested code is in a try/catch. I found some suggestions in this Github issue thread about using fail() or done.fail(), but I was unable to get this to fail the test from the imported module.

Best alternative I could think of would be to throw a console.warn() message so at least there's an obvious indication in the terminal of the missing mock. Otherwise, I'd imagine you'd have to build some sort of custom global Jest rule that fails when it hits an unmocked end point. This blog also looked like it might have some solutions, but I didn't have time to test them: Jest explicitly or arbitrarily force fail() a test.

I'm very curious about this. Let me know if you find any better solutions!