2016-05-13 8 views
2

Ich versuche einen Knopfklick mit Enzym zu simulieren. Ich bin in der Lage, einfache Tests zu schreiben, wenn ein Element rendert, aber die Spaßtests, wie Knopfklicks usw., sind nicht ausreichend.Die Taste zum Simulieren der Klick-Taste kann nicht gefunden werden. - Unit Testing Reagieren mit Mocha, Chai, Enzym

In diesem Beispiel wird der Fehler im Terminal ist:

1) Front End @Profile Component clicks a button : 
Error: This method is only meant to be run on single node. 0 found instead. 
    at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1093:17) 
    at ShallowWrapper.props (node_modules/enzyme/build/ShallowWrapper.js:532:21) 
    at ShallowWrapper.prop (node_modules/enzyme/build/ShallowWrapper.js:732:21) 
    at ShallowWrapper.simulate (node_modules/enzyme/build/ShallowWrapper.js:505:28) 
    at Context.<anonymous> (cmpnt-profile.spec.js:36:32) 

der Unit-Test ist:

 describe('Front End @Profile Component',() => { 
     const wrapper = shallow(<Profile/>); 

    ...(other tests here)... 
     it('clicks a button ',() => { 

     wrapper.find('button').simulate('click'); 
     expect(onButtonClick.calledOnce).to.equal(true); 
    }) 
}); 

die Komponente:

import _ from 'lodash'; 
import React, { Component, PropTypes } from 'react'; 
import { reduxForm } from 'redux-form'; 
import ExpireAlert from '../components/alert'; 
import SocialAccount from '../components/socialAccounts' 

const FIELDS = { 
    name : { 
     type : 'input', 
     label : 'name' 
    }, 
    username : { 
     type : 'input', 
     label: 'username' 
    }, 
    email : { 
     type : 'input', 
     label: 'email' 
    } 
}; 

let alert = false; 

export default class Profile extends Component { 

    componentWillReceiveProps(nextProps){ 
     if(nextProps.userIsUpdated){ 
     alert = !alert 
     } 
    } 

    handleSubmit(userData) { // update profile 
    userData.id = this.props.userInfo.id 
    this.props.updateUserInfo(userData) 
    } 

    renderField(fieldConfig, field) { // one helper per ea field declared 
     const fieldHelper = this.props.fields[field]; 
     return (
     <label>{fieldConfig.label} 
      <fieldConfig.type type="text" placeholder={fieldConfig.label} {...fieldHelper}/> 
      {fieldHelper.touched && fieldHelper.error && <div>{fieldHelper.error}</div>} 
     </label> 
    ); 
    } 

    render() { 
    const {resetForm, handleSubmit, submitting, initialValues} = this.props; 
     return (
     <div className="login"> 
      <div className="row"> 
      <div className="small-12 large-7 large-centered columns"> 
       <div className="component-wrapper"> 
       <ExpireAlert 
        set={this.props.userIsUpdated} 
        reset={this.props.resetAlert} 
        status="success" 
        delay={3000}> 
        <strong> That was a splendid update! </strong> 
       </ExpireAlert> 
       <h3>Your Profile</h3> 
       <SocialAccount 
        userInfo={this.props.userInfo} 
        unlinkSocialAcc={this.props.unlinkSocialAcc} 
       /> 
       <form className="profile-form" onSubmit={this.props.handleSubmit(this.handleSubmit.bind(this))}> 
        <div className="row"> 
        <div className="small-12 large-4 columns"> 
         <img className="image" src={this.props.userInfo.img_url}/> 
        </div> 
        <div className="small-12 large-8 columns"> 
         {_.map(FIELDS, this.renderField.bind(this))} 
        </div> 
        <div className="small-12 columns"> 
         <button type="submit" className="primary button expanded" disabled={submitting}> 
         {submitting ? <i/> : <i/>} Update 
         </button> 
        </div> 
        </div> 
       </form> 
       </div> 
      </div> 
      </div> 
     </div> 
    ); 
    } 
} 

const validate = values => { 
    const errors = {} 
    if (!values.name) { 
     errors.name = 'Name is Required' 
     } 
     if (!values.username) { 
     errors.username = 'Username is Required' 
     } else if (values.username.length > 30) { 
     errors.username = 'Must be 30 characters or less' 
     } 
     if (!values.email) { 
     errors.email = 'Email is Required' 
     } else if (!/^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) { 
     errors.email = 'Invalid email address' 
     } 
    return errors; 
} 

Profile.propTypes = { 
    fields: PropTypes.object.isRequired, 
    handleSubmit: PropTypes.func.isRequired, 
    resetForm: PropTypes.func.isRequired, 
    submitting: PropTypes.bool.isRequired 
} 

export default reduxForm({ 
    form: 'Profile', 
    fields: _.keys(FIELDS), 
    validate 
})(Profile) 

Irgendwelche Vorschläge geschätzt. Ich würde gerne einige erstaunliche Unit Tests machen!

Antwort

0

Sie haben zwei export default s in Ihrer Datei. Dies bedeutet natürlich, dass die zweite die erste überschreibt. Wenn Sie die reduxForm Version und die Komponente selbst exportieren möchten, sollten Sie das Wort default aus der Komponente entfernen.

Auf Ihrem Test, Sie shallow render, was bedeutet, keine Kinder gerendert werden. Da Sie die reduxForm importieren, wird nicht viel gerendert werden, definitiv nicht Ihre Profile. Deshalb, wenn Sie das default Schlüsselwort entfernt wie ich bereits erwähnt, wird Ihr Test anfangen zu arbeiten, wenn Sie es importieren einen benannten Import mit:

import { Profile } from 'path/to/component'; 

* Dies setzt voraus, Ihre Komponente verarbeiten kann nicht erhalten, was reduxForm versorgt sie mit, das ist gute Praxis sowieso, da Sie es einfacher finden werden, zu testen.

+0

Ich habe versucht, Standard von Klasse Profil, sowie die Redux-Form zu entfernen, und es führte zu einigen Fehlern. Hier ist eine davon, den Export aus der Klasse zu entfernen. –

+0

'bei Parser.pp.raise (/../fairshare/divvy/node_modules/babylon/index.js:1378:13) bei Parser.pp.unexpected' –

+0

ps. um es zu verdeutlichen, habe ich versucht, sie nacheinander zu entfernen, nicht beide gleichzeitig. –

2

ZekeDroid ist korrekt. Ein anderer Weg, um mit der Situation umzugehen, wäre die Verwendung von mount, was die Methode von Enzyme ist, Komponenten tief zu rendern, was bedeutet, dass der gesamte Baum von Komponenten gerendert wird. Dies würde anstelle eines Komponententests als Integrationstest betrachtet werden. ZekeDroid erwähnt "Dies setzt voraus, dass Ihre Komponente nicht in der Lage ist, das zu empfangen, was reduxForm liefert, was ohnehin gut ist, da Sie es einfacher testen können.", Und ich glaube, er bezieht sich auf Komponententests. Im Idealfall sollten Ihre Tests sowohl Komponententests als auch Integrationstests umfassen. Ich habe ein einfaches Projekt erstellt, um zu zeigen, wie man Unit- und Integrationstests mit Redux-Form durchführt. Siehe this repo.