How can I check in a jest test if a thunk action within a thunk action creator has been dispatched?

℡╲_俬逩灬. 提交于 2019-12-11 05:42:30

问题


Here's a generalized example:

// myActions.js
export const actionOne = () => (dispatch) => {
    dispatch(actionTwo());
};

export const actionTwo = () => ({
    type: 'SOME_TYPE',
});

I would like to test that actionTwo has been either called or dispatched, ideally without the test knowing anything about what is going on in actionTwo, because I have a different test that takes care of that.

I am using redux-mock-store to dispatch the tested action to a mocked store and calling store.getActions() to find out if the expected actions within the thunk action creator have been dispatched. I feel it is not the right way to go in this particular scenario because then the test would test more than it should. I really only want to know if actionTwo has been called at all.

I'm aware of spyOn and jest.mock, but I've been unable to use either to solve my problem. Here's what the generalized test looks like:

// myActions.test.js
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from 'myActions';

const mockStore = configureMockStore([thunk]);

test('actionOne', () => {
    const store = mockStore();

    return store.dispatch(actions.actionOne()).then(() => {
        // TODO: check if actions.actionTwo was called
    });
});

test('actionTwo', () => {
    const store = mockStore();

    return store.dispatch(actions.actionTwo()).then(() => {
        expect(store.getActions()).toEqual([{ type: 'SOME_TYPE' }]);
    }); 
});

I'm grateful for any suggestions!


回答1:


Took me a while, but I figured it out. It's not ideal (because it involves a small change to the tested code), but the closest to ideal that I could get.

// myActions.js
export const actionOne = () => (dispatch) => {
    dispatch(exports.actionTwo());
};

export const actionTwo = () => ({
    type: 'SOME_TYPE',
});

The important change is the exports.actionTwo(). That way, I make sure that I can overwrite the function's implementation from the outside (the test file) and the overwriting function will actually be called from within the imported file.

Now I can simply add something like the following to my test file:

beforeEach(() => {
    actions.actionTwo = jest.fn(() => () => Promise.resolve());
});

actionTwo is now being mocked and I can use toBeCalledWith and other expectations on it. If I wish to test its actual implementation within the same test file, I can store it in a variable before calling beforeEach, like:

const actionTwo = actions.actionTwo;

And then in the test setup for its implementation, I can overwrite the mock calling

actions.actionTwo = actionTwo;

That's it. Now I can make sure to ignore all side effects from an exported function and test it as an actual unit.




回答2:


It would be better to assert that two redux actions hit the store, not that actionOne calls the action creator.

Since all actions dispatched to the store must have an action type. Just make assertions about store.getActions():

test('actionOne', () => {
    const store = mockStore();
    return store.dispatch(actions.actionOne()).then(() => {
        expect(store.getActions()).to.have.length(2);
        expect(store.getActions()[0].type).to.equal('ACTION_ONE_TYPE');
        // make additional assertions about the first action

        expect(store.getActions()[1].type).to.equal('ACTION_TWO_TYPE');
    });
});


来源:https://stackoverflow.com/questions/45378214/how-can-i-check-in-a-jest-test-if-a-thunk-action-within-a-thunk-action-creator-h

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!