enzyme simulate submit form, Cannot read property 'value' of undefined

15,902

Solution 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.

Solution 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.');
    });

  });
Share:
15,902

Related videos on Youtube

j_quelly
Author by

j_quelly

I’m a Canadian frontend (user experience) engineer with fullstack proficiency working in San Francisco. I specialize in creating delightful, performant, user interfaces and experiences. My excellent product thinking and observations ensure there is no task I cannot handle.

Updated on September 28, 2022

Comments

  • j_quelly
    j_quelly 2 months

    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.');
        });
    
      });
    
  • j_quelly
    j_quelly almost 6 years
    I believe I do have to pass the event object otherwise I will receive an error TypeError: Cannot read property 'preventDefault' of undefined. airbnb.io/enzyme/docs/api/ShallowWrapper/simulate.html when enzyme simulate submits the form it invokes the onFormSubmit method which in turn invokes the event objects preventDefault method. Without passing a blank preventDefault method the test will throw an error. Examine the inputForm class to better understand.
  • j_quelly
    j_quelly almost 6 years
    I appreciate your comment, but I don't want to be managing state in two separate components. The inputForm class is a child component of a much larger application. All state management is handled by the parent component and passed as props where necessary. In time I will be updating the application to use Redux for better state management.
  • j_quelly
    j_quelly almost 6 years
    this is helpful, but I think you misunderstood the question. Yes, I do want to test submitting the form, but I want to test it with a value and again without a value.