酶模拟提交表单,无法读取未定义的 属性 'value'
enzyme simulate submit form, Cannot read property 'value' of undefined
我在用 jest 和 enzyme 测试一个组件时遇到了一些困难。我想做的是测试提交名称字段中没有值的表单。这将确保组件显示错误。但是,当我 运行 其余部分时,我的控制台出现错误:
TypeError: Cannot read property 'value' of undefined
我对前端测试和一般测试还很陌生。所以,我不完全确定我是否正确地使用酶进行此类测试。我不知道我的测试是否不正确,或者我是否刚刚编写了一个不容易测试的组件。如果这样可以更容易测试,我愿意更改我的组件吗?
组件
class InputForm extends Component {
constructor(props) {
super(props);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(e) {
e.preventDefault();
// this is where the error comes from
const name = this.name.value;
this.props.submitForm(name);
}
render() {
let errorMsg = (this.props.validationError ? 'Please enter your name.' : null);
return (
<form onSubmit={(e) => this.onFormSubmit(e)}>
<input
type="text"
placeholder="Name"
ref={ref => {
this.name = ref
}}
/>
<p className="error">
{errorMsg}
</p>
<input
type="submit"
className="btn"
value="Submit"
/>
</form>
);
}
}
InputForm.propTypes = {
submitForm: React.PropTypes.func.isRequired,
};
测试
// all other code omitted
// bear in mind I am shallow rendering the component
describe('the user does not populate the input field', () => {
it('should display an error', () => {
const form = wrapper.find('form').first();
form.simulate('submit', {
preventDefault: () => {
},
// below I am trying to set the value of the name field
target: [
{
value: '',
}
],
});
expect(
wrapper.text()
).toBe('Please enter your name.');
});
});
这个问题已经在 this thread 中讨论过了。
这个解决方案对我有用。
import { mount, shallow } from 'enzyme';
import InputForm from '../InputForm':
import React from 'react';
import { spy } from 'sinon';
describe('Form', () => {
it('submit event when click submit', () => {
const callback = spy();
const wrapper = mount(<InputForm />);
wrapper.find('[type="submit"]').get(0).click();
expect(callback).to.have.been.called();
});
});
它使用 mocha + chai 而不是 jest。但是你可以知道如何去做。
根据经验,您应该尽可能避免使用 refs,为什么?
对于您的情况,我建议更好的方法之一是:
class InputForm extends Component {
constructor(props) {
super(props);
this.state = {
name : ''
}
this.onFormSubmit = this.onFormSubmit.bind(this);
this.handleNameChange = this.handleNameChange.bind(this);
}
handleNameChange(e){
this.setState({name:e.target.value})
}
onFormSubmit(e) {
e.preventDefault();
this.props.submitForm(this.state.name);
}
render() {
let errorMsg = (this.props.validationError ? 'Please enter your name.' : null);
return (
<form onSubmit={(e) => this.onFormSubmit(e)}>
<input
type="text"
placeholder="Name"
onChange={this.handleNameChange}
/>
<p className="error">
{errorMsg}
</p>
<input
type="submit"
className="btn"
value="Submit"
/>
</form>
);
}
}
我想这会解决您的问题。
有了这个,你的测试应该 运行 没问题。
我认为您不需要传递事件对象来模拟提交事件。这应该有效。
describe('the user does not populate the input field', () => {
it('should display an error', () => {
const form = wrapper.find('form').first();
form.simulate('submit');
expect(
wrapper.find('p.error').first().text()
).toBe('Please enter your name.');
});
});
我在用 jest 和 enzyme 测试一个组件时遇到了一些困难。我想做的是测试提交名称字段中没有值的表单。这将确保组件显示错误。但是,当我 运行 其余部分时,我的控制台出现错误:
TypeError: Cannot read property 'value' of undefined
我对前端测试和一般测试还很陌生。所以,我不完全确定我是否正确地使用酶进行此类测试。我不知道我的测试是否不正确,或者我是否刚刚编写了一个不容易测试的组件。如果这样可以更容易测试,我愿意更改我的组件吗?
组件
class InputForm extends Component {
constructor(props) {
super(props);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(e) {
e.preventDefault();
// this is where the error comes from
const name = this.name.value;
this.props.submitForm(name);
}
render() {
let errorMsg = (this.props.validationError ? 'Please enter your name.' : null);
return (
<form onSubmit={(e) => this.onFormSubmit(e)}>
<input
type="text"
placeholder="Name"
ref={ref => {
this.name = ref
}}
/>
<p className="error">
{errorMsg}
</p>
<input
type="submit"
className="btn"
value="Submit"
/>
</form>
);
}
}
InputForm.propTypes = {
submitForm: React.PropTypes.func.isRequired,
};
测试
// all other code omitted
// bear in mind I am shallow rendering the component
describe('the user does not populate the input field', () => {
it('should display an error', () => {
const form = wrapper.find('form').first();
form.simulate('submit', {
preventDefault: () => {
},
// below I am trying to set the value of the name field
target: [
{
value: '',
}
],
});
expect(
wrapper.text()
).toBe('Please enter your name.');
});
});
这个问题已经在 this thread 中讨论过了。
这个解决方案对我有用。
import { mount, shallow } from 'enzyme';
import InputForm from '../InputForm':
import React from 'react';
import { spy } from 'sinon';
describe('Form', () => {
it('submit event when click submit', () => {
const callback = spy();
const wrapper = mount(<InputForm />);
wrapper.find('[type="submit"]').get(0).click();
expect(callback).to.have.been.called();
});
});
它使用 mocha + chai 而不是 jest。但是你可以知道如何去做。
根据经验,您应该尽可能避免使用 refs,为什么?
对于您的情况,我建议更好的方法之一是:
class InputForm extends Component {
constructor(props) {
super(props);
this.state = {
name : ''
}
this.onFormSubmit = this.onFormSubmit.bind(this);
this.handleNameChange = this.handleNameChange.bind(this);
}
handleNameChange(e){
this.setState({name:e.target.value})
}
onFormSubmit(e) {
e.preventDefault();
this.props.submitForm(this.state.name);
}
render() {
let errorMsg = (this.props.validationError ? 'Please enter your name.' : null);
return (
<form onSubmit={(e) => this.onFormSubmit(e)}>
<input
type="text"
placeholder="Name"
onChange={this.handleNameChange}
/>
<p className="error">
{errorMsg}
</p>
<input
type="submit"
className="btn"
value="Submit"
/>
</form>
);
}
}
我想这会解决您的问题。 有了这个,你的测试应该 运行 没问题。
我认为您不需要传递事件对象来模拟提交事件。这应该有效。
describe('the user does not populate the input field', () => {
it('should display an error', () => {
const form = wrapper.find('form').first();
form.simulate('submit');
expect(
wrapper.find('p.error').first().text()
).toBe('Please enter your name.');
});
});