Mocking promised based request with Jest

37,058

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();
  });
});
Share:
37,058
mfrachet
Author by

mfrachet

Love coding, love javascript

Updated on October 18, 2020

Comments

  • mfrachet
    mfrachet over 3 years

    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]}]
    
  • mfrachet
    mfrachet over 7 years
    I can't see the spy in this implementation :/. But thank you for your answer
  • Andreas Köberle
    Andreas Köberle over 7 years
    Have you tried expect(spy.mock) instead of expect(spy)?
  • Andreas Köberle
    Andreas Köberle over 7 years
    And you have to return the dispatcher from your test.
  • mfrachet
    mfrachet over 7 years
    I've tried but no way. And it seems that the node-module isn't mocked at all. When I run my test without my backend, it sends the request and throw errors
  • Andreas Köberle
    Andreas Köberle over 7 years
    Ok, so how do you import fetch into your module or do you use the native JS implementation?
  • mfrachet
    mfrachet over 7 years
    Import fetch from 'node-fetch';
  • Andreas Köberle
    Andreas Köberle over 7 years
    maybe it helps when you create the mock before importing the file you wanna test