Come testare l’unità React-Redux Connected Components?

Sto usando Mocha, Chai, Karma, Sinon, Webpack per i test di unità.

Ho seguito questo link per configurare il mio ambiente di test per React-Redux Code.

https://medium.com/@scbarrus/how-to-get-test-coverage-on-react-with-karma-babel-and-webpack-c9273d805063#.7kcckz73r

Posso testare con successo il mio codice javascript action e riduttori, ma quando si tratta di testare i miei componenti viene sempre generato un errore.

import React from 'react'; import TestUtils from 'react/lib/ReactTestUtils'; //I like using the Test Utils, but you can just use the DOM API instead. import chai from 'chai'; // import sinon from 'sinon'; import spies from 'chai-spies'; chai.use(spies); let should = chai.should() , expect = chai.expect; import { PhoneVerification } from '../PhoneVerification'; let fakeStore = { 'isFetching': false, 'usernameSettings': { 'errors': {}, 'username': 'sahil', 'isEditable': false }, 'emailSettings': { 'email': '[email protected]', 'isEmailVerified': false, 'isEditable': false }, 'passwordSettings': { 'errors': {}, 'password': 'showsomestarz', 'isEditable': false }, 'phoneSettings': { 'isEditable': false, 'errors': {}, 'otp': null, 'isOTPSent': false, 'isOTPReSent': false, 'isShowMissedCallNumber': false, 'isShowMissedCallVerificationLink': false, 'missedCallNumber': null, 'timeLeftToVerify': null, '_verifiedNumber': null, 'timers': [], 'phone': '', 'isPhoneVerified': false } } function setup () { console.log(PhoneVerification); // PhoneVerification.componentDidMount = chai.spy(); let output = TestUtils.renderIntoDocument(); return { output } } describe('PhoneVerificationComponent', () => { it('should render properly', (done) => { const { output } = setup(); expect(PhoneVerification.prototype.componentDidMount).to.have.been.called; done(); }) }); 

Questo errore seguente viene fornito con il codice precedente.

 FAILED TESTS: PhoneVerificationComponent ✖ should render properly Chrome 48.0.2564 (Mac OS X 10.11.3) Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. 

Ho provato a passare dalle spie dei sinoniti alle chai-spie.

Come devo testare i miei componenti React-Redux Connected (Smart Components)?

Un modo più carino per farlo è quello di esportare sia il componente semplice che il componente racchiuso nella connessione. L’esportazione nominata sarebbe il componente, il predefinito è il componente spostato:

 export class Sample extends Component { render() { let { verification } = this.props; return ( 

This is my awesome component.

); } } const select = (state) => { return { verification: state.verification } } export default connect(select)(Sample);

In questo modo puoi importare normalmente nella tua app, ma quando si tratta di test puoi importare la tua esportazione nominata usando import { Sample } from 'component' .

Puoi testare il tuo componente connesso e penso che dovresti farlo. Potresti voler testare prima il componente non connesso, ma ti suggerisco di non avere una copertura completa del test senza testare anche il componente connesso.

Di seguito è riportato un estratto non testato di ciò che faccio con Redux ed Enzyme. L’idea centrale è di utilizzare il provider per colbind lo stato in prova al componente connesso nel test.

 import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; import SongForm from '../SongForm'; // import the CONNECTED component // Use the same middlewares you use with Redux's applyMiddleware const mockStore = configureMockStore([ /* middlewares */ ]); // Setup the entire state, not just the part Redux passes to the connected component. const mockStoreInitialized = mockStore({ songs: { songsList: { songs: { songTags: { /* ... */ } } } } }); const nullFcn1 = () => null; const nullFcn2 = () => null; const nullFcn3 = () => null; const wrapper = mount( // enzyme    ); const formPropsFromReduxForm = wrapper.find(SongForm).props(); // enzyme expect( formPropsFromReduxForm ).to.be.deep.equal({ screen: 'add', songTags: initialSongTags, disabled: false, handleFormSubmit: nullFcn1, handleModifySong: nullFcn2, handleDeleteSong: nullFcn3, }); ===== ../SongForm.js import React from 'react'; import { connect } from 'react-redux'; const SongForm = (/* object */ props) /* ReactNode */ => { /* ... */ return ( 
....
}; const mapStateToProps = (/* object */ state) /* object */ => ({ songTags: state.songs.songTags }); const mapDispatchToProps = () /* object..function */ => ({ /* ... */ }); export default connect(mapStateToProps, mapDispatchToProps)(SongForm)

Potresti voler creare un negozio con Redux puro. redux-mock-store è solo una versione leggera di questo significato per i test.

Potresti voler utilizzare react-addons-test-utils invece di Enjyme di airbnb.

Uso il chai-enzima di airbnb per avere delle opzioni di aspettativa a conoscenza di React. Non era necessario in questo esempio.

Il problema con la risposta accettata è che stiamo esportando qualcosa inutilmente solo per poterlo testare. E esportare un corso solo per testarlo non è una buona idea secondo me.

Ecco una soluzione più ordinata senza bisogno di esportare nulla tranne il componente connesso:

Se stai usando il jest, puoi prendere in giro il metodo connect per restituire tre cose:

  1. mapStateToProps
  2. mapDispatchToProps
  3. ReactComponent

Fare così è piuttosto semplice. Ci sono 2 modi: mock in linea o mock globali.

1. Usando la derisione in linea

Aggiungi lo snippet seguente prima della funzione descriva il test.

 jest.mock('react-redux', () => { return { connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({ mapStateToProps, mapDispatchToProps, ReactComponent }), Provider: ({ children }) => children } }) 

Prova a creare 2 file, uno con il componente stesso, non essendo a conoscenza di alcun archivio o altro (PhoneVerification-component.js). Poi il secondo (PhoneVerification.js), che userete nella vostra applicazione e che restituisce solo il primo componente sottoscritto per lo store tramite la funzione connect , qualcosa come

 import PhoneVerificationComponent from './PhoneVerification-component.js' import {connect} from 'react-redux' ... export default connect(mapStateToProps, mapDispatchToProps)(PhoneVerificationComponent) 

Quindi puoi testare il tuo componente “stupido” richiedendo PhoneVerification-component.js nel tuo test e fornendogli i necessari oggetti di scena. Non c’è motivo di test già testato (connect decorator, mapStateToProps, mapDispatchToProps etc …)