Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking promised based request with Jest

I'm trying to unit test a function using Jest, and I'm having some trouble dealing with jest mock modules (the equivalent of rewire or proxyquire in nodejs world).

I'm actually trying to test that a spy has been called on the mocked module with some parameters. Here's the function that I want to test.

NB : the current test only concerns the "fetch(...)" part, I m trying to test that fetch has been called with the good parameter.

export const fetchRemote = slug => {
    return dispatch => {
        dispatch(loading());
        return fetch(Constants.URL + slug)
            .then(res => res.json())
            .then(cmp => {
                if (cmp.length === 1) {
                    return dispatch(setCurrent(cmp[0]));
                }
                return dispatch(computeRemote(cmp));
            });
    };
};

The function returned acts as a closure, and so "captures" the node-fetch external module that I want to mock.

Here's the test I m trying to make pass green :

it('should have called the fetch function wih the good const parameter and slug', done => {
            const slug = 'slug';
            const spy = jasmine.createSpy();
            const stubDispatch = () => Promise.resolve({json: () => []});
            jest.mock('node-fetch', () => spy);
            const dispatcher = fetchRemote(slug);
            dispatcher(stubDispatch).then(() => {
                expect(spy).toHaveBeenCalledWith(Constants.URL + slug);
                done();
            });
        });

EDIT : The first answer helped a lot concerning writing the test, I have now the following one :

it('should have called the fetch function wih the good const parameter and slug', done => {
            const slug = 'slug';
            const stubDispatch = () => null;
            const spy = jest.mock('node-fetch', () => Promise.resolve({json: () => []}));
            const dispatcher = fetchRemote(slug);
            dispatcher(stubDispatch).then(() => {
                expect(spy).toHaveBeenCalledWith(Constants.URL + slug);
                done();
            });
        });

But now, here's the error I have :

 console.error node_modules/core-js/modules/es6.promise.js:117
      Unhandled promise rejection [Error: expect(jest.fn())[.not].toHaveBeenCalledWith()

      jest.fn() value must be a mock function or spy.
      Received:
        object: {"addMatchers": [Function anonymous], "autoMockOff": [Function anonymous], "autoMockOn": [Function anonymous], "clearAllMocks": [Function anonymous], "clearAllTimers": [Function anonymous], "deepUnmock": [Function anonymous], "disableAutomock": [Function anonymous], "doMock": [Function anonymous], "dontMock": [Function anonymous], "enableAutomock": [Function anonymous], "fn": [Function anonymous], "genMockFn": [Function bound getMockFunction], "genMockFromModule": [Function anonymous], "genMockFunction": [Function bound getMockFunction], "isMockFunction": [Function isMockFunction], "mock": [Function anonymous], "resetModuleRegistry": [Function anonymous], "resetModules": [Function anonymous], "runAllImmediates": [Function anonymous], "runAllTicks": [Function anonymous], "runAllTimers": [Function anonymous], "runOnlyPendingTimers": [Function anonymous], "runTimersToTime": [Function anonymous], "setMock": [Function anonymous], "unmock": [Function anonymous], "useFakeTimers": [Function anonymous], "useRealTimers": [Function anonymous]}]
like image 276
mfrachet Avatar asked Oct 17 '16 07:10

mfrachet


People also ask

How do you mock a Promise in Jest?

In order to mock asynchronous code in Jest, more specifically Promises, you can use the mockResolvedValue function. This will mock the return value of the Promise to be 42. In order to test a Promise in Jest, you need to turn your it block into async in order to use the await keyword in front of an expect statement.

How do you test Promise reject Jest?

Try-catch with async/await (bad) It looks like using try-catch with async/await is the easiest way to achieve this as the rejected value is thrown: it("rejects (bad)", async () => { try { await promiseMe("Error"); } catch (e) { expect(e). toEqual("Error"); } }); But wait.

How do you mock a post request on Jest?

Use jest. mock() and post. mockImplementation() will do this. You can get the actual callback function passed in post function in your test case.

How do you do mocking in Jest?

Mocking Modules​ export default Users; Now, in order to test this method without actually hitting the API (and thus creating slow and fragile tests), we can use the jest. mock(...) function to automatically mock the axios module.

How do I mock a promise in jest?

In short, 3 simple steps to mock promise using Jest. Import the desired mock js module into your test file using require (). Using jest.mock ('js-filepath') to enable you to setup mocking for all functions within that module.

What does jest's mock function do?

When you run jest.mock ('axios'), Jest replaces every function in the axios module with empty "mock" functions. These mock functions essentially do nothing and return undefined:

How do I mock an API call in jest?

To mock an API call in a function, you just need to do these 3 steps: Import the module you want to mock into your test file. jest.mock () the module. Use .mockResolvedValue (<mocked response>) to mock the response.

How to mock a promise that is fulfilled and returning value?

We can use mockResolvedValue () in order to mock promise that is fulfilled and returning value. While for mocking promise that is rejected, we can use mockRejectedValue (). Refer to the example test below for more details.


1 Answers

First of all you need to return a promise when testing async code. And your spy needs to return a resolved or rejected promise.

it('should have called the fetch function wih the good const parameter and slug', done => {
  const slug = 'successPath';
  const stubDispatch = () => Promise.resolve({ json: () => [] });
  spy = jest.mock('node-fetch', (path) => {
    if (path === Constants.URL + 'successPath') {
      return Promise.resolve('someSuccessData ')
    } else {
      return Promise.reject('someErrorData')
    }
  });
  const dispatcher = fetchRemote(slug);
  return dispatcher(stubDispatch).then(() => {
    expect(spy).toHaveBeenCalledWith(Constants.URL + slug);
    done();
  });
});
like image 71
Andreas Köberle Avatar answered Oct 14 '22 10:10

Andreas Köberle