简体   繁体   中英

React and jest mock module

I am creating an application in which I use redux and node-fetch for remote data fetching.

I want to test the fact that I am well calling the fetch function with a good parameter.

This way, I am using jest.mock and jasmine.createSpy methods :

it('should have called the fetch method with URL constant', () => {
            const spy = jasmine.createSpy('nodeFetch');
            spy.and.callFake(() => new Promise(resolve => resolve('null')));
            const mock = jest.mock('node-fetch', spy);
            const slug = 'slug';
            actionHandler[FETCH_REMOTE](slug);
            expect(spy).toHaveBeenCalledWith(Constants.URL + slug);
        });

Here's the function that I m trying to test :

[FETCH_REMOTE]: slug => {
        return async dispatch => {
            dispatch(loading());
            console.log(fetch()); // Displays the default fetch promise result
            await fetch(Constants.URL + slug);
            addLocal();
        };
    }

AS you can see, I am trying to log the console.log(fetch()) behavior, and I am having the default promise to resolve given by node-fetch, and not the that I've mock with Jest and spied with jasmine.

Do you have an idea what it doesn't work ?

EDIT : My test displayed me an error like my spy has never been called

Your action-handler is actually a action handler factory. In actionHandler[FETCH_REMOTE] , you are creating a new function. The returned function taskes dispatch as a parameter and invokes the code you are showing.
This means that your test code will never call any function on the spy, as the created function is never invoked.

I think you will need to create a mock dispatch function and do something like this:

let dispatchMock = jest.fn(); // create a mock function
actionHandler[FETCH_REMOTE](slug)(dispatchMock);

EDIT:

To me, your actionHandler looks more like an actionCreator , as it is usually called in redux terms, though I personally prefer to call them actionFactories because that is what they are: Factories that create actions.
As you are using thunks (?) your actionCreater (which is misleadingly named actionHandler ) does not directly create an action but another function which is invoked as soon as the action is dispatched. For comparison, a regular actionCreator looks like this:

updateFilter: (filter) => ({type: actionNames.UPDATE_FILTER, payload: {filter: filter}}),

A actionHandler on the other hand reacts to actions being dispatched and evaluates their payload.

Here is what I would do in your case:

Create a new object called actionFactories like this:

const actionFactories = {

    fetchRemote(slug): (slug) => {
        return async dispatch => {
            dispatch(loading());
            console.log(fetch()); // Displays the default fetch promise result
            let response = await fetch(Constants.URL + slug);

            var responseAction;
            if (/* determine success of response */) {
                responseAction = actionFactories.fetchSuccessful(response);
            } else {
                responseAction = actionFactories.fetchFailed();
            }

            dispatch(responseAction);
        };
    }

    fetchFailed(): () => ({type: FETCH_FAILED, }),
    fetchSuccessful(response): () => ({type: FETCH_FAILED, payload: response })
};

Create an actionHandler for FETCH_FAILED and FETCH_SUCCESSFUL to update the store based on the response.

BTW: Your console.log statement does not make much sense too me, since fetch just returns a promise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM