How to test mapStateToProps using React Redux and Jest?

a 夏天 提交于 2021-02-11 06:11:51

问题


When I create a test for my connected React component where I want to test the mapStateToProps logic I run into a problem which I'm not sure how to solve.

Error message

Expected: 1
Received: undefined

  24 |     it('should show previously rolled value', () => {
  25 |         // test that the state values were correctly passed as props
> 26 |         expect(wrapper.props().lastRolledNumber).toBe(1);

When I check the wrapper.props() it only returns the store object and no properties.

To make sure it's not my code I have found an example that should work to simplify it, but I get the same problem when using that exact version in my app (option #2, https://jsramblings.com/2018/01/15/3-ways-to-test-mapStateToProps-and-mapDispatchToProps.html)

I think it might have to do with the React 16+ version, which I found mentioned here: https://airbnb.io/enzyme/docs/api/ReactWrapper/props.html

.props() => Object

Returns the props object for the root node of the wrapper. It must be a single-node wrapper. This method is a reliable way of accessing the props of a node; wrapper.instance().props will work as well, but in React 16+, stateless functional components do not have an instance. See .instance() => ReactComponent

Does anyone know how to test this in a good way to see that the logic is working as expected without exporting the private mapStateToProps function directly?

Component

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

// Component 1 - "Base component"
// Exporting it is a good practice for testing its own logic
export const Dice = ({ lastRolledNumber, onRollDice }) => (
    <div>        
        <p>The last rolled number was {lastRolledNumber}.</p>
        <button onClick={onRollDice}>Roll dice</button>
    </div>
);

Dice.propTypes = {
    lastRolledNumber: PropTypes.number.isRequired,
    onRollDice: PropTypes.func.isRequired
}

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

const mapDispatchToProps = (dispatch) => ({
    onRollDice: () => dispatch({ type: 'ROLL_DICE' })
});

// Component 2 - Container component
// Export it as a default export
export default connect(mapStateToProps, mapDispatchToProps)(Dice);

Test

import React from 'react';
import { shallow } from 'enzyme';
import '../test-config'; // Setup Enzyme & Adapter

import DiceContainer from './Dice';

// Create the mock store
import configureMockStore from 'redux-mock-store';
const mockStore = configureMockStore();

describe('Dice', () => {
    let wrapper, store;

    beforeEach(() => {
        const initialState = {
            lastRolledNumber: 1
        };
        store = mockStore(initialState);
        // Shallow render the container passing in the mock store
        wrapper = shallow(
            <DiceContainer store={store} />
        );
    });

    it('should show previously rolled value', () => {
        // test that the state values were correctly passed as props
        expect(wrapper.props().lastRolledNumber).toBe(1);
    });

    it('should roll the dice again when button is clicked', () => {
        // test that the component events dispatch the expected actions 
        wrapper.simulate('rollDice');

        const actions = store.getActions();
        expect(actions).toEqual([ { type: 'ROLL_DICE' } ]);
    });
});

回答1:


You are almost there. You need to call .dive() method so that you can get the Dice component rather than the DiceContainer component which is wrapped by the connect HOC of react-redux module.

Short answer:

wrapper = shallow(<DiceContainer store={store} />).dive();

A Completed working example:

index.jsx:

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

export const Dice = ({ lastRolledNumber, onRollDice }) => (
  <div>
    <p>The last rolled number was {lastRolledNumber}.</p>
    <button onClick={onRollDice}>Roll dice</button>
  </div>
);

Dice.propTypes = {
  lastRolledNumber: PropTypes.number.isRequired,
  onRollDice: PropTypes.func.isRequired,
};

const mapStateToProps = (state) => ({
  lastRolledNumber: state.lastRolledNumber,
});

const mapDispatchToProps = (dispatch) => ({
  onRollDice: () => dispatch({ type: 'ROLL_DICE' }),
});

export default connect(mapStateToProps, mapDispatchToProps)(Dice);

index.test.jsx:

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

const mockStore = configureMockStore();

describe('Dice', () => {
  let wrapper;
  let store;

  beforeEach(() => {
    const initialState = {
      lastRolledNumber: 1,
    };
    store = mockStore(initialState);
    wrapper = shallow(<DiceContainer store={store} />).dive();
  });

  it('should show previously rolled value', () => {
    expect(wrapper.props().lastRolledNumber).toBe(1);
  });

  it('should roll the dice again when button is clicked', () => {
    wrapper.simulate('rollDice');
    const actions = store.getActions();
    expect(actions).toEqual([{ type: 'ROLL_DICE' }]);
  });
});

Unit test results:

 PASS  src/stackoverflow/59771991/index.test.jsx (9.645s)
  Dice
    ✓ should show previously rolled value (19ms)
    ✓ should roll the dice again when button is clicked (2ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        11.505s

Test coverage html report:



来源:https://stackoverflow.com/questions/59771991/how-to-test-mapstatetoprops-using-react-redux-and-jest

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