2016-05-13 70 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