Redux:如何测试连接组件?

时间:2016-08-17 21:28:07

标签: unit-testing reactjs redux enzyme

我正在使用Enzyme对我的React组件进行单元测试。我知道为了测试原始的未连接组件,我必须只是导出它并测试它(我已经完成了)。我已经设法为连接的组件编写了一个测试,但我真的不确定这是否正确,以及我想要测试连接组件的确切内容。

Container.jsx

import {connect} from 'react-redux';
import Login from './Login.jsx';
import * as loginActions from './login.actions';

const mapStateToProps = state => ({
  auth: state.auth
});
const mapDispatchToProps = dispatch => ({
  loginUser: credentials => dispatch(loginActions.loginUser(credentials))

});
export default connect(mapStateToProps, mapDispatchToProps)(Login);

Container.test.js

import React from 'react';
import {Provider} from 'react-redux';
import {mount, shallow} from 'enzyme';
import {expect} from 'chai';
import LoginContainer from '../../src/login/login.container';
import Login from '../../src/login/Login';


describe('Container Login', () => {
  it('should render the container component', () => {
    const storeFake = state => ({
      default: () => {
      },
      subscribe: () => {
      },
      dispatch: () => {
      },
      getState: () => ({ ...state })
    });
    const store = storeFake({
      auth: {
        sport: 'BASKETBALL'
      }
    });

    const wrapper = mount(
      <Provider store={store}>
        <LoginContainer />
      </Provider>
    );

    expect(wrapper.find(LoginContainer).length).to.equal(1);
    const container = wrapper.find(LoginContainer);
    expect(container.find(Login).length).to.equal(1);
    expect(container.find(Login).props().auth).to.eql({ sport: 'BASKETBALL' });
  });
});

3 个答案:

答案 0 :(得分:21)

这是一个有趣的问题。

我通常会导入容器和组件来进行测试。对于容器测试,我使用redux-mock-store。组件测试用于测试异步功能。例如,在您的情况下,登录过程是使用sinon存根的异步函数。这是一个相同的片段,

import React from 'react';
import {Provider} from 'react-redux';
import {mount, shallow} from 'enzyme';
import {expect} from 'chai';
import LoginContainer from '../../src/login/login.container';
import Login from '../../src/login/Login';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { stub } from 'sinon';

const mockStore = configureMockStore([thunk]);

describe('Container Login', () => {
  let store;
  beforeEach(() => {
    store = mockStore({
      auth: {
        sport: 'BASKETBALL',
      },
    });
  });
  it('should render the container component', () => {
    const wrapper = mount(
      <Provider store={store}>
        <LoginContainer />
      </Provider>
    );

    expect(wrapper.find(LoginContainer).length).to.equal(1);
    const container = wrapper.find(LoginContainer);
    expect(container.find(Login).length).to.equal(1);
    expect(container.find(Login).props().auth).to.eql({ sport: 'BASKETBALL' });
  });

  it('should perform login', () => {
    const loginStub = stub().withArgs({
      username: 'abcd',
      password: '1234',
    });
    const wrapper = mount(<Login
      loginUser={loginStub}
    />);
  wrapper.find('button').simulate('click');
  expect(loginStub.callCount).to.equal(1);
  });
});

答案 1 :(得分:3)

正如您所指出的,我通常这样做的方式是导出未连接的组件,并测试它。

export {Login};

这是一个例子。 Source of the componentsource of the tests

对于包装组件,我不会为这些组件创建测试,因为我的映射(mapStateToPropsmapDispatchToProps)通常非常简单。如果我想测试一个包装好的组件,我真的只是测试那些地图。所以我会选择明确测试,而不是以包装形式重新测试整个组件。

有两种方法可以测试这些功能。一种方法是导出模块本身的功能。

即;

export {mapStateToProps, mapDispatchToProps}

我不是这方面的忠实粉丝,因为我不希望应用中的其他模块访问它们。在我的测试中,我有时使用babel-plugin-rewire来访问&#34;范围内&#34;变量,这就是我在这种情况下会做的事情。

这看起来像是:

import {
  Login, __Rewire__
}

const mapStateToProps = __Rewire__.__get__('mapStateToProps');

describe('mapStateToProps', () => { ... });

答案 2 :(得分:0)

如果遇到路由器问题,可以考虑将路由器库添加到测试文件中,例如:

import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { mount } from 'enzyme';
import ReadDots from './ReadDots';

const storeFake = state => ({
  default: () => {
  },
  subscribe: () => {
  },
  dispatch: () => {
  },
  getState: () => ({ ...state })
});

const store = storeFake({
  dot: {
    dots: [
      {
        id: '1',
        dot: 'test data',
        cost: '100',
        tag: 'pocket money'
      }
    ]
  }
});

describe('<ReadDots />', () => {
  it('should render ReadDots component', () => {
    const component = mount(
      <Provider store={store}>
        <Router>
          <ReadDots />
        </Router>
      </Provider>
    );
    expect(component.length).toEqual(1);
  });
});