6

So I would like to test mapStateToProps and mapDispatchToProps with Enzyme/Jest.

I have a component DrawerAvatar like this:

DrawerAvatar.js

const mapStateToProps = state => ({
  isAuthenticated: state.authReducer.isAuthenticated
});

export default compose(
  connect(mapStateToProps, null)
)(DrawerAvatar);

DrawerAvatar.test.js

import configureMockStore from 'redux-mock-store';
import connectedDrawerAvatar, { DrawerAvatar } from './DrawerAvatar';

const mockStore = configureMockStore();

it('mapStateToProps should return the right value', () => {
  const initialState = {
    someState: 123
  };
  const store = mockStore(initialState);
  const wrapper = shallow(<connectedDrawerAvatar store={store} />);
  expect(wrapper.props().someState).toBe(123);
});

However, this doesn't work because wrapper.props().someState returns undefined... So I have no clue how to test mapStatesToProps along with redux-mock-store using the connected component.

I don't know neither how to test mapDispatchToProps ..! I've tried the methods providing in this blog but it doesn't work.

Thank you very much !

EDIT: This works, but I'm not sure if it really tests the mapStateToProps... Can someone confirm that this is the right way to test mapStateToProps ? DrawerAvatar.test.js

  it('mapStateToProps should return the right value', () => {
    const initialState = {
      isAuthenticated: false
    };
    const mockStore = configureMockStore();
    const store = mockStore(initialState);

    const wrapper = shallow(<connectedDrawerAvatar store={store} />);
    expect(wrapper.props().store.getState().isAuthenticated).toBe(false);
  });
filipyoo
  • 347
  • 1
  • 7
  • 15
  • have a look at using mount instead of shallow and check out the second param which allows you to pass context – patrick Aug 21 '18 at 07:17
  • I've checked it, but I don't really understand what the context really is... Can you please provide some code snippet to illustrate what you have in mind ? – filipyoo Aug 21 '18 at 07:34
  • For mapDispatchToProps testing, you can check https://stackoverflow.com/a/55814950/1897654 – Uday Sravan K Apr 26 '19 at 06:00

3 Answers3

6

One way I found from : redux discussion on github is

import React from 'react';
import { shallow } from 'enzyme';
import configureMockStore from 'redux-mock-store';

import ConnectedDrawerAvatar from './DrawerAvatar';
describe('DrawerAvatar', ()=> {
    const mockStore = configureMockStore();

    it.each([true, false], 'receives correct value from store as props', (value)=> {
        const initialState = { authReducer: { isAuthenticated: value } }
        const store = mockStore(initialState)

        const wrapper = shallow(<ConnectedDrawerAvatar store={store} />)
        expect(wrapper.props().isAuthenticated).toBe(value)
    })
})
KungWaz
  • 1,918
  • 3
  • 36
  • 61
Rajnikant
  • 2,176
  • 24
  • 23
2

You can also try this instead :

In my opinion Testing mapStateToProps(), you need to identify the props for the particular state. Also used provider which makes the components available that are wrapped in Connect() function.

import React from 'react';
import { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import ConnectedDrawerAvatar from './DrawerAvatar';

describe('DrawerAvatar', ()=> {
  let component;
  let store;
  let value;

 beforeEach(() => {
    const initialState = {
        authReducer: { isAuthenticated: value }
    };
    store = mockStore(initialState);
    component = shallow(<Provider store={store}><ConnectedDrawerAvatar/></Provider>);
  });

 it('should return exact value from the store(props)', () => {
     expect(component.props().isAuthenticated).toBe(value);
  });


});

Hope this helps!

Akhil
  • 56
  • 1
0

Easiest way to test that is to that mapStateToProps directly, like this:

export const mapStateToProps = state => ({
  isAuthenticated: state.authReducer.isAuthenticated
});

and have a test like this:

it('mapStateToProps should return the right value', () => {
  const mockedState = {
    authReducer: {
      isAuthenticated: false
    }
  };
  const state = mapStateToProps(mockedState);
  expect(state).toBeFalsy();
});

But I dont really see why you should do that.

IMO you should not test connected components. Just export the container class and test it directly.

The reason why one should not test component connection is that it is tested well in the library itself so by testing that you don't really add any value.

Moyote
  • 1,169
  • 9
  • 20
  • Thx for your answer ! But exporting a private method like mapStateToProps might not be a good idea... And I'm already using redux-mock-store, but this package is only for testing actions-related stuff AFAIK... – filipyoo Aug 21 '18 at 10:20
  • @filipyoo sry, i noticed that you use it already and edited my answer a bit. Why exporting that is not a good idea, can you be more explicit? If that's the piece of code you really want to test, I don't see any problem in exporting that. – Moyote Aug 21 '18 at 10:23
  • 2
    Yep I'm aware of the fact that `connect` is already fully tested from the package, but not mapStateToProps and mapDispatchToProps. And `you’re exposing private code of the app as public just for testing, which is a bit of a code smell` according to this [blog post](https://jsramblings.com/2018/01/15/3-ways-to-test-mapStateToProps-and-mapDispatchToProps.html) – filipyoo Aug 21 '18 at 10:26
  • That's right. But is it really worse than rendering the whole thing which takes more time? Unit tests should also be fast. But if you really want to test them, this should do it, right? expect(wrapper.props().isAuthenticated).toBeFalsy(); – Moyote Aug 21 '18 at 10:34
  • Here's an example how you validate props: http://airbnb.io/enzyme/docs/api/ReactWrapper/props.html – Moyote Aug 21 '18 at 10:37
  • +1 on exporting `mapStateToProps()` and testing it directly. I always export `mapStateToProps()` and `mapDispatchToProps()` and the unconnected component and test them directly. Clean, fast, simple. – Brian Adams Aug 22 '18 at 03:08