web-dev-qa-db-fra.com

Redux: Comment tester un composant connecté?

J'utilise Enzyme pour tester unitairement mes composants React. Je comprends que pour tester le composant brut non connecté, je devrais simplement l'exporter et le tester (I ' J'ai réussi à écrire un test pour le composant connecté, mais je ne suis vraiment pas sûr que ce soit la bonne façon et aussi ce que je voudrais exactement tester pour le composant connecté.

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

C'est une question intéressante.

J'importe habituellement à la fois le conteneur et le composant pour faire les tests. Pour les tests de conteneurs que j'utilise, redux-mock-store. Le test des composants sert à tester les fonctions asynchrones. Par exemple, dans votre cas, le processus de connexion est une fonction asynchrone utilisant des stubs sinon. Voici un extrait de la même chose,

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

Comme vous l'avez souligné, la façon dont je le fais habituellement consiste à exporter également le composant non connecté et à le tester.

c'est à dire.

export {Login};

Voici un exemple. Source du composant , et source des tests .

Pour le composant encapsulé, je ne crée pas de tests pour ceux-ci car mes mappages (mapStateToProps et mapDispatchToProps) sont généralement très simples. Si je voulais tester un composant encapsulé, je testerais vraiment ces cartes. C'est donc ce que je choisirais de tester explicitement, plutôt que de retester le composant entier sous une forme enveloppée.

Il existe deux façons de tester ces fonctions. Une façon serait d'exporter les fonctions dans le module lui-même.

c'est à dire.;

export {mapStateToProps, mapDispatchToProps}

Je ne suis pas un grand fan de cela, car je ne voudrais pas que d'autres modules de l'application y accèdent. Dans mes tests, j'utilise parfois babel-plugin-rewire pour accéder aux variables "in-scope", c'est donc ce que je ferais dans cette situation.

Cela pourrait ressembler à quelque chose comme:

import {
  Login, __Rewire__
}

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

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

Si nous avons un problème de routeur, nous pouvons envisager d'ajouter la bibliothèque du routeur dans le fichier de test, par exemple:

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