2016-12-18 1 views
0

Ich lerne, wie React/Redux-Komponenten mit Enzym zu testen. Die Komponente nimmt den App-Level-Status als Requisiten an. Wenn ich den Test ausführen, bekomme ich die Fehler:React/Redux Testing w/Enzym

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).

TypeError: Cannot read property 'contextTypes' of undefined

mit meinem console.log von wrapper in der folgenden Testdatei Protokollierung als undefined.

Ich weiß, dass hier etwas nicht stimmt und habe ein paar Stunden damit verbracht, das herauszufinden. Kann jemand etwas Offensichtliches in der Art sehen, wie ich die Komponente importiere und versuche, sie zu benutzen? Ich kann nicht herausfinden, warum es undefined ist. Vielen Dank im Voraus für jede Hilfe oder Einsicht!

BackendDisplay.js

import React from 'react'; 
import { connect } from 'react-redux'; 
import moment from 'moment'; 

var BackendDisplay = React.createClass({ 

    render() { 

    const { username, node_version, app_path, timestamp } = this.props.loginState; 
    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a'); 

    return (
     <div> 
     <h1>Welcome, {username}!</h1> 
     <p><span className="bold">Node Version:</span> {node_version}</p> 
     <p><span className="bold">Application Path:</span> {app_path}</p> 
     <p><span className="bold">Date/Time:</span> {dateTime}</p> 
     </div> 
    ); 
    } 
}); 

const mapStateToProps = function(store) { 
    return store; 
} 

module.exports = connect(mapStateToProps)(BackendDisplay); 

BackendDisplay.test.js

'use strict'; 

import React from 'react'; 
import {shallow} from 'enzyme'; 
import { connect } from 'react-redux'; 
import { BackendDisplay } from '../components/BackendDisplay'; 

describe('<BackendDisplay />',() => { 

    it('Correctly displays username, node_version, app_path, and timestamp',() => { 

    const wrapper = shallow(<BackendDisplay />); 
    console.log(wrapper); 

    }); 

}); 

nach Änderungen Editiert: BackendDisplay.js

BackendDisplay.test.js

'use strict'; 

import React from 'react'; 
import {shallow} from 'enzyme'; 
import { connect } from 'react-redux'; 
import store from '../store'; 
import { Provider } from 'react-redux'; 
import ConnectedBackendDisplay, {BackendDisplay} from '../components/BackendDisplay'; 

describe('<BackendDisplay />',() => { 

    it('Correctly displays username, node_version, app_path, and timestamp',() => { 

    const wrapper = shallow(
     <Provider store={store}> 
     <BackendDisplay /> 
     </Provider> 
    ); 

    console.log(wrapper.find(BackendDisplay)); 
    expect(wrapper.find(BackendDisplay).length).to.equal(1); 

    }); 

}); 

Fehlermeldung: TypeError: Enzyme::Selector expects a string, object, or Component Constructor

Antwort

3

Ihr BackendDisplay ist ein Container-Komponente und es ist an der Redux Speicher durch die Verwendung des connect verbunden api.

Sie sollten die undekorierte Komponente zu Testzwecken exportieren. Da es nicht verziert ist, wird diese exportierte Komponente nicht mit der Connect-Komponente von react-redux umhüllt.

var BackendDisplay = React.createClass({ 

    render() { 

    const { username, node_version, app_path, timestamp } = this.props.loginState; 
    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a'); 

    return (
     <div> 
     <h1>Welcome, {username}!</h1> 
     <p><span className="bold">Node Version:</span> {node_version}</p> 
     <p><span className="bold">Application Path:</span> {app_path}</p> 
     <p><span className="bold">Date/Time:</span> {dateTime}</p> 
     </div> 
    ); 
    } 
}); 

Dann können Sie es wie folgt importieren die Testarbeit

import {BackendDisplay} from 'BackendDisplay' 

Als Bonus machen können Sie auch die dekorierte BackendDisplay Komponente exportieren, indem Sie die folgende Zeile zu ändern

module.exports = connect(mapStateToProps)(BackendDisplay); 

zu

export default connect(mapStateToProps)(BackendDisplay); 

So importieren sowohl die dekorierten und undecorated Komponenten

import ConnectedBackendDisplay, {BackendDisplay} from 'BackendDisplay' 

ConnectedBackendDisplay auf der dekorierten Komponente bezieht, die durch die unbenannte Export (Export Standard BackendDisplay) exportiert wird.

Wir geben ihm nur diesen Namen, so dass es klar ist, ist es in einer Connect-Komponente verpackt.

Ich habe die folgende Komponente aktualisiert, um Export-Standard zu verwenden, der einen unbenannten Export gibt.

BackendDisplay

import React from 'react'; 
import { connect } from 'react-redux'; 
import moment from 'moment'; 

export const BackendDisplay = React.createClass({ 

    render() { 

    const { username, node_version, app_path, timestamp } = this.props; 
    // removed reference to this.props.loginState 

    const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a'); 

    return (
     <div> 
     <h1>Welcome, {username}!</h1> 
     <p><span className="bold">Node Version:</span> {node_version}</p> 
     <p><span className="bold">Application Path:</span> {app_path}</p> 
     <p><span className="bold">Date/Time:</span> {dateTime}</p> 
     </div> 
    ); 
    } 
}); 

const mapStateToProps = function(store) { 
    return store; 
} 

export default connect(mapStateToProps)(BackendDisplay); 

Hier ist der Test-Suite sowohl als gestaltet und undecorated Komponente mit Enzym Testen der obigen Komponente zu demonstrieren.

Ich verwende die Chai-Bibliothek, um Testaussagen zu erleichtern. Die jsdom-Bibliothek wird auch verwendet, um eine DOM-Umgebung zu erstellen, sodass wir Komponenten mit der Mount-Funktion von Enzyme testen können, die Komponenten vollständig rendert.

Test

'use strict'; 
import React from 'react'; 
import jsdom from 'jsdom' 
import { expect } from 'chai' 
import { shallow , mount} from 'enzyme'; 
import { Provider } from 'react-redux'; 
import ConnectedBackendDisplay, // decorated component 
    {BackendDisplay} from 'app/components/BackendDisplay'; // undecorated component 
// for mocking a store to test the decorated component 
import configureMockStore from 'redux-mock-store'; 

// create a fake DOM environment so that we can use Enzyme's mount to 
// test decorated components 
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>') 
global.document = doc 
global.window = doc.defaultView 


describe.only('<BackendDisplay />',() => { 

    it('undecorated component correctly displays username',() => { 
     // define the prop we want to pass in 
     const username = 'Foo' 
     // render the component with the prop 
     const wrapper = mount(<BackendDisplay username={username} />); 
     // test that the text of the first <p> equals username prop that we passed in  
     expect(wrapper.find('h1').first().text()).to.equal(username); 
    }); 

    it('decorated component correctly displays username',() => { 
     // define the prop we want to pass in 
     const username = 'Foo' 
     const initialState = { } 
     // create our mock store with an empyty initial state 
     const store = configureMockStore(initialState) 

     // render the component with the mockStore 
     const wrapper = shallow(<Provider store={store}> 
           <ConnectedBackendDisplay username={username}/> 
           </Provider>); 

     // test that the text of the first <p> equals username prop that we passed in  
     expect(wrapper.find('h1').first().text()).to.equal(username); 
    }); 
}); 
+0

Dank für Ihre schnelle Antwort Dank! Ist dies die Standardmethode zum Testen von Komponenten, die mit dem Geschäft verbunden sind? Würden Sie normalerweise eine separate Datei für die undekorierte Komponente erstellen, und wenn ja, wo würden Sie diese Datei platzieren? Danke, dass du einem Test-Neuling hilfst :) – MizzKFizzle

+0

Ich füge das zu meiner Antwort hinzu. Mit einem Wort nein würden die Tests für diese Komponente alle in der gleichen Testdatei sein. – therewillbecode

+0

Huch. Alle möglichen neuen Fehler. Kämpfe heute Morgen mit dem Bus. – MizzKFizzle