web-dev-qa-db-ja.com

Redux:接続されたコンポーネントをテストする方法は?

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' });
  });
});
18
Umair Sarfraz

これは興味深い質問です。

私は通常、コンテナとコンポーネントの両方をインポートしてテストを行います。私が使用するコンテナテストの場合、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);
  });
});
24
anoop

あなたが指摘したように、私が通常これを行う方法は、未接続のコンポーネントもエクスポートし、それをテストすることです。

つまり.

export {Login};

以下に例を示します。 コンポーネントのソース 、および テストのソース

ラップされたコンポーネントの場合、マッピング(mapStateToPropsおよびmapDispatchToProps)は一般的に非常に単純であるため、それらのテストは作成しません。ラップされたコンポーネントをテストする場合は、実際にそれらのマップをテストするだけです。したがって、これらは、ラップされた形式でコンポーネント全体を再テストするのではなく、明示的にテストすることを選択するものです。

これらの機能をテストするには2つの方法があります。 1つの方法は、モジュール内の関数をエクスポートすることです。

すなわち;

export {mapStateToProps, mapDispatchToProps}

アプリ内の他のモジュールがそれらにアクセスしたくないので、私はこれの大ファンではありません。私のテストでは、「 babel-plugin-rewire 」を使用して「スコープ内」変数にアクセスすることがあるため、この状況でそれを行います。

次のようになります。

import {
  Login, __Rewire__
}

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

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

ルーターに問題がある場合は、ルーターlibをテストファイルに追加することを検討できます。例:

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);
  });
});
0
Damon Wu