Mocking promised based request with Jest
javascript, jestjs, node.js, reactjs, unit-testing
Solution
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();
});
});
Problem
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]}] ```