3

I am a newbie with jest and I am writing unit tests to my react application, which is using redux and which is written with Typescript.

I have my container component with this piece of code:

const mapDispatchToProps = (dispatch: Dispatch<any>) => ({
    onSelectScenario: (selectedScenario: any) => {
        dispatch(selectScenario(selectedScenario));
    }
});

I want to write a unit test checking that when I call this prop from the test (onSelectScenario), the dispatch method will be called with the right params.

Any idea how to spy on this dispatch?

This is my unit test where I call the prop method:

it('should dispatch', () => {
    component.props().onSelectScenario('New Selected Scenario');
});

And this is the setup of the tests where I define my container component providing the mocked store:

const mockStore = configureMockStore();
let store = mockStore({
    scenarios: ['Scenario 1', 'Scenario 2']
});
let component: ShallowWrapper<any, any>;

describe('ScenarioListGroupContainer Component', () => {
    beforeEach(() => {
        component = shallow(<ScenarioListGroupContainer store={store} />);
    });
    // ...
});
skyboyer
  • 22,209
  • 7
  • 57
  • 64
quirimmo
  • 9,800
  • 3
  • 30
  • 45
  • 1
    FYI you're testing wether `mapDispatchToProps` works as expected. This is part of redux however, and you should trust that the library itself has tested its functionality. Usually only the actual component is tested, as far as calling the props goes. They are easy to spy on and most of the time shallow rendering is also enough. – timotgl Apr 05 '18 at 12:23
  • Nope, I am testing if my logic inside the method matched to props through redux is working as expected. I just want to see that calling that prop, added through redux, there is a call to dispatch passing the right params – quirimmo Apr 05 '18 at 12:27
  • Fair enough. Keep in mind that you can also pass a simple object instead for `mapDispatchToProps`. It automatically binds each action to be dispatched and the object basically just becomes a list of actions: `const mapDispatchToProps = { selectScenario, otherAction, etc. };` Then the component would call `this.props.selectScenario`. This way there would be nothing to test. You really only need the "long" way of declaring `mapDispatchToProps` if multiple dispatches or other side-effects need to happen when a single prop is called. – timotgl Apr 05 '18 at 12:44
  • 1
    @quirimmo you rolled back an update to add a language tag for code formatting which made this question more readable. I think it was appropriate, is there a reason not to allow code formatting on this question? – Brandon Culley Sep 06 '18 at 19:34

3 Answers3

6

If it helps anyone, this is what I'm using:

const spy = jest.spyOn(store, 'dispatch');
Shaun Saker
  • 447
  • 5
  • 11
1

The best solution I've found so far (any better suggestion is more than welcome) is the following, keeping exactly the same code provided in my question:

it('should dispatch the select scenario action', () => {
    component.props().onSelectScenario('New Selected Scenario');
    expect(store.getActions()).toEqual([{ 
        type: 'SELECT_SCENARIO', 
        selectedScenario: 'New Selected Scenario' 
    }]);
});

So you manually call your prop and then you check if the action has been dispatched correctly in the store

quirimmo
  • 9,800
  • 3
  • 30
  • 45
0

I hear you @quirimmo. This is how I do it.

In component -

export const mapDispatchToProps = (dispatch) => ({
  onAction : (data) => dispatch(someAction()),
});

In test - import {mapDispatchToProps} from './component'; import {someAction} from './actions';

const actions = [ someAction() ];
const mockDispatch = (action) => action; // just echo the action
const mockMDTP = mapDispatchToProps(mockDispatch);
Object.keys(mockMDTP).forEach((key) => {
   expect(actions.contains(mockMDTP[key]())).toBe(true);
  });
});

Explanation -

  1. Creates an actions array. This would contain all the structures of the actions in MDTP.
  2. Then mocks and echo dispatch.
  3. Checks the keys of the object to match actions array.

Hope this helps !

Shobhit Chittora
  • 1,209
  • 8
  • 13
  • Thanks a lot for your answer but this is not what I am looking for. Here you are doing exactly what @timotgl was saying in the comments. Here you are testing if `mapDispatchToProps` works fine. Instead I want to test only the body of the method I am mapping as prop through `mapDispatchToProps`. And however, you define again your logic in unit tests, and you're testing your unit test logic instead that the source file for which you're writing the test – quirimmo Apr 05 '18 at 23:48