我正试图用Enzyme模拟按钮点击。如果元素呈现,我已经能够编写简单的测试,但是按钮点击等有趣的测试却不尽如人意。
在此示例中,终端中的错误是:
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._%+-]+@[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 :(得分:2)
ZekeDroid是正确的。处理这种情况的另一种方法是使用mount
,这是Enzyme深度渲染组件的方式,意味着渲染整个组件树。这将被视为集成测试,而不是单元测试。 ZekeDroid提到“这假设您的组件可以处理不接收reduxForm提供的任何内容,这无论如何都是好的做法,因为您会发现它更容易测试。”,我相信他正在引用单元测试。理想情况下,您的测试应包括单元测试和集成测试。我创建了一个简单的项目来展示如何使用redux-form进行单元测试和集成测试。请参阅this repo。
答案 1 :(得分:0)
您的文件中有两个export default
个。这自然意味着第二个覆盖了第一个。如果您真的希望能够导出reduxForm
版本和组件本身,就像您应该进行测试一样,那么请从组件中删除单词default
。
在您的测试中,您shallow
渲染,意味着不渲染任何子项。由于您导入了reduxForm
,因此无法呈现任何内容,绝对不是您的Profile
。因此,如果您删除了我提到的default
关键字,那么当您使用命名导入导入测试时,测试将开始工作:
import { Profile } from 'path/to/component';
*这假设您的组件可以处理不接收任何reduxForm
提供的内容,这无论如何都是很好的做法,因为您会发现它更容易测试。