2016-02-01 16 views
37

Ich verwende Mocha, Chai, Karma, Sinon, Webpack für Komponententests.Wie Unit React-Redux verbundene Komponenten testen?

Ich folgte diesem Link, um meine Testumgebung für React-Redux Code zu konfigurieren.

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

Ich kann meine Handlung und Reduzierungen JavaScript-Code erfolgreich testen, aber wenn es meine Komponenten zu testen kommt es immer einige Fehler werfen.

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(<PhoneVerification {...fakeStore}/>); 
    return { 
     output 
    } 
} 

describe('PhoneVerificationComponent',() => { 
    it('should render properly', (done) => { 
     const { output } = setup(); 
     expect(PhoneVerification.prototype.componentDidMount).to.have.been.called; 
     done(); 
    }) 
}); 

Dieser folgende Fehler kommt mit dem obigen Code auf.

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. 

Versuchte Wechsel von Sinon Spione zu Chai-Spione.

Wie soll ich meine React-Redux Connected Komponenten (Smart Components) testen?

+0

Wie exportieren Sie Ihre Komponente? Verwenden Sie benannte Exporte oder nur die Export-Standard? 'Import {PhoneVerification} from ' ../ PhoneVerification '; 'ist deine problematische Zeile, wenn du das machst, bekommst du undefined, wenn du keinen benannten Export machst. –

+0

Ich benutze Named Export. – Ayushya

+0

Ich habe auch ein ähnliches Setup und bekomme eine ähnliche Fehlermeldung Irgendwelche Fortschritte dabei? Danke. – FujiRoyale

Antwort

35

Eine schönere Möglichkeit, dies zu tun ist, exportieren Sie sowohl Ihre einfache Komponente, und die Komponente in Verbindung verpackt. Der genannte Export die Komponente wäre, die Standardeinstellung ist die umhüllte Komponente:

Auf diese Weise können Sie normalerweise in Ihrer Anwendung importieren können, aber wenn es darum geht zu testen Sie Ihren Namen Export mit import { Sample } from 'component' importieren.

+0

Vielen Dank, es funktioniert! – Ayushya

+0

Könnten Sie bitte meinen Beitrag als Antwort akzeptieren? –

+0

großartige Lösung. Vielen Dank! –

1

Versuchen Sie, 2 Dateien zu erstellen, eine mit der Komponente selbst, die keine Filiale oder irgendetwas kennt (PhoneVerification-component.js). Dann zweite (PhoneVerification.js), die Sie in Ihrer Anwendung verwenden wird und die nur gibt die erste Komponente über connect Funktion speichern abonniert, so etwas wie

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

Dann können Sie Ihre „dumme“ Komponente testen, indem Sie erfordern PhoneVerification-component.js in Ihrem Test und es mit notwendigen verspotteten Requisiten versehen. Es gibt keinen Punkt des Tests bereits getestet (connect Decorator, mapStateToProps, mapDispatchToProps etc ...)

+0

Danke für die Lösung. – Ayushya

+0

Hey @ george.cz, beschreiben Sie 'mapStateToProps' als" bereits getestet. "Wie geht es Ihnen Testen Sie 'mapStateToProps' und' mapDispatchToProps'? Exportieren Sie sie aus dem Container und Versuche für die exportierten Funktionen erstellen? – stone

+1

@skypecakes Ich glaube, er meinte ['connect' selbst] (https://github.com/reactjs/react-redux/blob/master/test/components/connect.spec.js). – falsarella

10

Sie können Ihre verbundene Komponente testen und ich denke, dass Sie dies tun sollten. Vielleicht möchten Sie zuerst die nicht verbundene Komponente testen, aber ich schlage vor, dass Sie keine vollständige Testabdeckung haben werden, ohne auch die verbundene Komponente zu testen.

Unten ist ein ungeprüfter Auszug dessen, was ich mit Redux und Enzym mache. Die zentrale Idee ist, Provider zu verwenden, um den Status im Test mit der verbundenen Komponente im Test zu verbinden.

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 
     <Provider store={store}> 
      <SongForm 
      screen="add" 
      disabled={false} 
      handleFormSubmit={nullFcn1} 
      handleModifySong={nullFcn2} 
      handleDeleteSong={nullFcn3} 
      /> 
     </Provider> 
    ); 

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 (
     <form onSubmit={handleSubmit(handleFormSubmit)}> 
      .... 
     </form> 

}; 

const mapStateToProps = (/* object */ state) /* object */ => ({ 
    songTags: state.songs.songTags 
}); 
const mapDispatchToProps =() /* object..function */ => ({ /* ... */ }); 

export default connect(mapStateToProps, mapDispatchToProps)(SongForm) 

Sie möchten vielleicht ein Geschäft mit reinem Redux erstellen. redux-mock-store ist nur eine leichtgewichtige Version, die zum Testen gedacht ist.

Sie können react-addons-test-utils anstelle von Airbnb-Enzym verwenden.

Ich benutze Airbnb Chai-Enzym, um React-aware erwarten Optionen haben. Es wurde in diesem Beispiel nicht benötigt.

+0

Sorry @Tarjei Huse, aber ich habe deine Bearbeitung zurückgesetzt. ist, was Redux bietet, um in React einzuhaken. Ihre Bearbeitung ist fest codiert, wie sie es derzeit macht. Aber ich möchte nicht, dass mein Code ausgesetzt jemals seine Implementierung ändern. – JohnSz

0

Das Problem mit der akzeptierten Antwort ist, dass wir etwas unnötig exportieren, nur um es zu testen. Und eine Klasse zu exportieren, nur um es zu testen, ist meiner Meinung nach keine gute Idee.

Hier ist eine sauberere Lösung ohne die Notwendigkeit, etwas anderes als die angeschlossene Komponente exportieren:

Wenn Sie Scherz verwenden, können Sie connect Methode drei Dinge zurückzukehren verspotten:

  1. mapStateToProps
  2. mapDispatchToProps
  3. ReactComponent

Das ist ziemlich einfach. Es gibt 2 Möglichkeiten: Inline-Mocks oder globale Mocks.

1. Verwenden von Inline-Mock

Fügen Sie den folgenden Code-Schnipsel vor der Funktion des Test beschreiben.

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

2. Datei Mit Mock

  1. Erstellen Sie eine Datei __mocks__/react-redux.js in der Wurzel (wo package.json befindet)
  2. den folgenden Ausschnitt in der Datei hinzufügen.

module.exports = { 
 
    connect: (mapStateToProps, mapDispatchToProps) => (reactComponent) => ({ 
 
    mapStateToProps, 
 
    mapDispatchToProps, 
 
    ReactComponent, 
 
    }), 
 
    Provider: ({children}) => children 
 
};

Nach verspotten würden Sie in der Lage sein, den Zugriff auf alle oben genannten drei mit Container.mapStateToProps, Container.mapDispatchToProps und Container.ReactComponent.

Container kann einfach tun

import Container from '<path>/<fileName>.container.js'

Hoffe, es hilft importiert werden.

Beachten Sie, dass wenn Sie Datei Mock verwenden. Die mocked Datei wird global für alle Testfälle verwendet (außer Sie tun jest.unmock('react-redux')) vor dem Testfall.

Verwandte Themen