【问题标题】:How to test mapStateToProps using React Redux and Jest?如何使用 React Redux 和 Jest 测试 mapStateToProps?
【发布时间】:2020-05-03 10:26:02
【问题描述】:

当我为我想要测试 mapStateToProps 逻辑的连接的 React 组件创建测试时,我遇到了一个我不知道如何解决的问题。

错误信息

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);

当我检查 wrapper.props() 时,它只返回 store 对象,没有属性。

为了确保这不是我的代码,我找到了一个可以简化它的示例,但是在我的应用程序中使用该确切版本时我遇到了同样的问题(选项 #2,https://jsramblings.com/2018/01/15/3-ways-to-test-mapStateToProps-and-mapDispatchToProps.html

我认为这可能与 React 16+ 版本有关,我发现这里提到过:https://airbnb.io/enzyme/docs/api/ReactWrapper/props.html

.props() => 对象

返回包装器根节点的 props 对象。一定是 单节点包装器。此方法是一种可靠的访问方法 节点的道具; wrapper.instance().props 也可以,但是在 React 16+,无状态功能组件没有实例。 参见 .instance() => ReactComponent

有谁知道如何在不直接导出私有 mapStateToProps 函数的情况下以一种很好的方式对其进行测试以查看逻辑是否按预期工作?

组件

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);

测试

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' } ]);
    });
});

【问题讨论】:

    标签: javascript reactjs react-redux jestjs enzyme


    【解决方案1】:

    在我的例子中,我可以通过这个来编写带有渲染的测试 -

    import React from 'react';
    import '@testing-library/jest-dom';
    import {
        screen, cleanup, render,
    } from '@testing-library/react';
    import { Provider } from 'react-redux';
    import configureMockStore from 'redux-mock-store';
    const store = configureMockStore()({
        headerState: {
            showBack: false,
        },
    });    
    const mockProps = { ... };
    describe('Component', () => {
        beforeAll(() => {
            render(
                <Provider store={store}>
                    <Component {...mockProps} />
                </Provider>,
            );
        });
        afterAll(cleanup);
    
        test('Test', () => {
            screen.debug();
        });
    });
    

    【讨论】:

      【解决方案2】:

      你快到了。您需要调用.dive() 方法,这样您才能获得Dice 组件,而不是由connect HOC 封装的react-redux 模块的DiceContainer 组件。

      简答:

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

      一个完整的工作示例:

      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' }]);
        });
      });
      

      单元测试结果:

       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
      

      测试覆盖率html报告:

      【讨论】:

      • 谢谢!你救了我,为此苦苦挣扎了一段时间……有趣的是我错过了 .dive() 部分。添加了它,现在它也适用于我:)
      猜你喜欢
      • 2019-01-27
      • 2019-03-22
      • 2020-09-17
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      相关资源
      最近更新 更多