问题
I'm having some difficulty testing a component with jest and enzyme. What I would like to do is test submitting the form without a value in the name field. This will make certain that the component is displaying an error. However, when I run the rest I am getting an error in my console:
TypeError: Cannot read property 'value' of undefined
I'm fairly new to front-end testing, and testing in general. So, I'm not entirely sure I'm using enzyme correctly for this type of test. I don't know if my tests are incorrect or if I've just written a component that is not easily tested. I'm open to changing my component if that will make it easier to test?
Component
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,
};
Test
// 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.');
});
});
回答1:
As a rule of thumb, you should avoid using refs whenever possible, why? here
In your case, I suggest one of the better approaches could be :
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>
);
}
}
I guess this will solve your problem. With this your test should run fine.
回答2:
I think that you don't need to pass event object to simulate the submit event. This should work.
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.');
});
});
回答3:
The issue has been discussed in this thread already.
And this solution works for me.
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();
});
});
Its using mocha + chai instead of jest. But you can get an idea of how to do it.
来源:https://stackoverflow.com/questions/41295768/enzyme-simulate-submit-form-cannot-read-property-value-of-undefined