Redux: как протестировать подключенный компонент?

Я использую Enzyme для модульного тестирования моих компонентов React. Я понимаю, что для тестирования необработанного несвязанного компонента мне нужно просто экспортировать его и протестировать (я это сделал). Мне удалось написать тест для подключенного компонента, но я действительно не уверен, что это правильный путь, а также то, что именно я хочу проверить для подключенного компонента.

контейнер.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);

контейнер.тест.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' });
  });
});

2 ответов


Это интересный вопрос.

Я обычно импортирую как контейнер, так и компонент для тестирования. Для тестирования контейнеров я использую,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);
  });
});

как вы указали, способ, которым я обычно это делаю, - это экспортировать не подключенный компонент и проверить это.

то есть

export {Login};

вот пример. источник компонента и источник тесты.

для обернутого компонента я не создаю тесты для них, потому что мои сопоставления (mapStateToProps и mapDispatchToProps), как правило, очень простой. Если бы я хотел протестировать завернутый компонент, я бы просто тестировал их карты. Таким образом, это то, что я бы выбрал для явного тестирования, а не для повторного тестирования всего компонента в обернутой форме.

есть два способа проверить эти функции. Одним из способов было бы экспортировать функции внутри самого модуля.

то есть;

export {mapStateToProps, mapDispatchToProps}

Я не большой поклонник этого, потому что я не хотел бы, чтобы другие модули в приложении для доступа к ним. В моих тестах, я иногда использую babel-plugin-rewire для доступа к " in-scope" переменные, вот что я бы сделал в этой ситуации.

Это может выглядеть так:

import {
  Login, __Rewire__
}

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

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