2016-05-13 69 views
2

我试图模拟一个按钮点击酶。我已经能够编写简单的测试,如果一个元素呈现,但有趣的测试,如按钮点击等不足。无法找到按钮来模拟点击单元测试反应瓦特/摩卡,柴,酶

在这个例子中在终端中的错误是:

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) 

单元测试是:

 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); 
    }) 
}); 

的组分是:

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) 

任何建议表示赞赏。我很想做一些惊人的单元测试!

回答

0

您的文件上有两个export default s。这自然意味着第二个压倒一切。如果您确实希望能够导出reduxForm版本和组件本身,就像您应该进行测试一样,然后从组件中删除default这个词。

在你的测试中,你shallow渲染,意味着没有儿童呈现。由于您导入reduxForm,没有什么会呈现,绝对不是您的Profile。因此,如果你删除default关键字就像我提到的,你的测试将开始当您导入它使用一个名为导入工作:

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

*假设你的组件能够处理未收到任何reduxForm它与提供,这是无论如何,你会发现它更容易测试。

+0

我试着从类Profile以及redux表格中删除默认值,并导致了一些错误。这里有一个从课堂上删除出口。 –

+0

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

+0

ps。为了澄清,我试图一次删除一个,而不是同时删除它们。 –

2

ZekeDroid是正确的。处理这种情况的另一种方法是使用mount,这是Enzyme深层渲染组件的方式,这意味着渲染了整个组件树。这将被认为是一个集成测试,而不是单元测试。 ZekeDroid提到:“这假定你的组件不能接收任何与ReduxForm提供的内容,这是一个很好的练习,因为你会发现它更容易测试。”我相信他正在引用单元测试。理想情况下,你的测试应该包括单元测试和集成测试。我创建了一个简单的项目,演示如何使用redux-form进行单元测试和集成测试。见this repo