【问题标题】:enzyme simulate submit form, Cannot read property 'value' of undefined酶模拟提交表单,无法读取未定义的属性“值”
【发布时间】:2017-05-08 19:47:05
【问题描述】:

我在用玩笑和酶测试组件时遇到了一些困难。我想做的是测试在名称字段中没有值的情况下提交表单。这将确保组件显示错误。但是,当我运行其余部分时,我的控制台中出现错误:

TypeError: 无法读取未定义的属性“值”

我对前端测试和一般测试还很陌生。所以,我不完全确定我在这种类型的测试中正确使用了酶。我不知道我的测试是否不正确,或者我刚刚编写了一个不容易测试的组件。如果这样可以更容易测试,我愿意更改我的组件吗?

组件

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

  });

【问题讨论】:

    标签: javascript reactjs jestjs enzyme


    【解决方案1】:

    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 而不是玩笑。但是您可以了解如何操作。

    【讨论】:

    • 这很有帮助,但我认为您误解了这个问题。是的,我确实想测试提交表单,但我想用一个值测试它,然后再用一个值测试它。
    【解决方案2】:

    我认为你不需要传递事件对象来模拟提交事件。这应该可以。

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

    【讨论】:

    • 我相信我必须传递事件对象,否则我会收到错误TypeError: Cannot read property 'preventDefault' of undefinedairbnb.io/enzyme/docs/api/ShallowWrapper/simulate.html 当酶模拟提交表单时,它调用onFormSubmit 方法,该方法又调用事件对象preventDefault 方法。如果不传递空白的preventDefault 方法,测试将引发错误。检查inputForm 类以更好地理解。
    【解决方案3】:

    根据经验,您应该尽可能避免使用 refs,为什么? here

    在您的情况下,我建议更好的方法之一是:

      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>
              );
          }
        }
    

    我想这会解决你的问题。 有了这个,你的测试应该可以正常运行了。

    【讨论】:

    • 感谢您的评论,但我不想在两个单独的组件中管理状态。 inputForm 类是一个更大的应用程序的子组件。所有状态管理都由父组件处理,并在必要时作为 props 传递。我将及时更新应用程序以使用 Redux 进行更好的状态管理。
    猜你喜欢
    • 2019-07-05
    • 1970-01-01
    • 2018-09-05
    • 2017-06-16
    • 2021-07-31
    • 2020-04-06
    • 2021-05-25
    • 2017-09-24
    • 2020-10-26
    相关资源
    最近更新 更多