最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React, how to simulate user input for unit testing? - Stack Overflow

programmeradmin17浏览0评论

I have been trying to unit test a react component that takes in user input. More specifically I'm trying to test the onChange function within the react component. However I can't seem to set the input value, I've tried a few different ways suggested on the internet and none seem to work. Below is the component I'm trying to test.

class Input extends Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    /* Check if max length has been set. If max length has been
    set make sure the user input is less than max Length, otherwise
    return before updating the text string. */
    if(this.props.maxLength) {
      if(event.target.value.length > this.props.maxLength) {
        return;
      }
    }
    this.setState({ value: event.target.value });
  }

  render () {
    const { disabled, label, maxLength, multiline, type, value, ...others} = this.props;
    const theme = themeable(others.theme);

    let inputClassName = classNames({
      "input": type !== 'checkbox',
      "checkbox": type == 'checkbox',
      disabled,
      multiline,
      value,
      [`${this.props.className}`]: !!this.props.className
    });

    return (
      <div {...theme(1, 'container')}>
        {this.props.label ? <label htmlFor={this.props.htmlFor} {...theme(2, 'label')}>{label}</label> : null}
          <input value={this.state.value} {...theme(3, ...inputClassName)} onChange={this.handleChange} type={type} />
      </div>
    );
  }
}

I found this issue: and tried the suggestions towards the bottom, I keep getting either undefined or a blank string. I tried levibuzolic's suggestion of using enzyme's simulate change, which can be seen below. However this just returns AssertionError: expected '' to equal 'abcdefghij'

it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    result.find('input').simulate('change', {target: {value: 'abcdefghijk'}});
    expect(result.state().value).to.equal("abcdefghij");
});

Then I tried takkyuuplayer's suggestion which is also below. This also fails with AssertionError: expected '' to equal 'abcdefghij'

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    result.find('input').node.value = 'abcdefghijk';
    expect(result.state().value).to.equal("abcdefghij");
  });

I found this article: .f4gcjbaak and tried their way which also failed.

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    let input = result.find('input');
    input.get(0).value = 'abcdefghijk';
    input.simulate('change');
    expect(result.state().value).to.equal("abcdefghij");
  });

Finally I tried using the react test utils as suggested by Simulating text entry with reactJs TestUtils, below is the code I tried, however this failed with the error message: TypeError: Cannot read property '__reactInternalInstance$z78dboxwwtrznrmuut6wjc3di' of undefined

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    let input = result.find('input');
    TestUtils.Simulate.change(input, { target: { value: 'abcdefghijk' } });
    expect(result.state().value).to.equal("abcdefghij");
  });

So how does one simulate user input so they can test the onChange function?

I have been trying to unit test a react component that takes in user input. More specifically I'm trying to test the onChange function within the react component. However I can't seem to set the input value, I've tried a few different ways suggested on the internet and none seem to work. Below is the component I'm trying to test.

class Input extends Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    /* Check if max length has been set. If max length has been
    set make sure the user input is less than max Length, otherwise
    return before updating the text string. */
    if(this.props.maxLength) {
      if(event.target.value.length > this.props.maxLength) {
        return;
      }
    }
    this.setState({ value: event.target.value });
  }

  render () {
    const { disabled, label, maxLength, multiline, type, value, ...others} = this.props;
    const theme = themeable(others.theme);

    let inputClassName = classNames({
      "input": type !== 'checkbox',
      "checkbox": type == 'checkbox',
      disabled,
      multiline,
      value,
      [`${this.props.className}`]: !!this.props.className
    });

    return (
      <div {...theme(1, 'container')}>
        {this.props.label ? <label htmlFor={this.props.htmlFor} {...theme(2, 'label')}>{label}</label> : null}
          <input value={this.state.value} {...theme(3, ...inputClassName)} onChange={this.handleChange} type={type} />
      </div>
    );
  }
}

I found this issue: https://github.com/airbnb/enzyme/issues/76 and tried the suggestions towards the bottom, I keep getting either undefined or a blank string. I tried levibuzolic's suggestion of using enzyme's simulate change, which can be seen below. However this just returns AssertionError: expected '' to equal 'abcdefghij'

it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    result.find('input').simulate('change', {target: {value: 'abcdefghijk'}});
    expect(result.state().value).to.equal("abcdefghij");
});

Then I tried takkyuuplayer's suggestion which is also below. This also fails with AssertionError: expected '' to equal 'abcdefghij'

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    result.find('input').node.value = 'abcdefghijk';
    expect(result.state().value).to.equal("abcdefghij");
  });

I found this article: https://medium.com/javascript-inside/testing-in-react-getting-off-the-ground-5f569f3088a#.f4gcjbaak and tried their way which also failed.

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    let input = result.find('input');
    input.get(0).value = 'abcdefghijk';
    input.simulate('change');
    expect(result.state().value).to.equal("abcdefghij");
  });

Finally I tried using the react test utils as suggested by Simulating text entry with reactJs TestUtils, below is the code I tried, however this failed with the error message: TypeError: Cannot read property '__reactInternalInstance$z78dboxwwtrznrmuut6wjc3di' of undefined

  it('Make sure inputted text is shorter than max length', function() {
    const result = mount(<Input maxLength={10}></Input>);
    let input = result.find('input');
    TestUtils.Simulate.change(input, { target: { value: 'abcdefghijk' } });
    expect(result.state().value).to.equal("abcdefghij");
  });

So how does one simulate user input so they can test the onChange function?

Share Improve this question edited May 23, 2017 at 11:53 CommunityBot 11 silver badge asked Jan 3, 2017 at 20:24 2trill2spill2trill2spill 1,3832 gold badges20 silver badges42 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 14

You seem to have a bug in your Input component. When event.target.value.length > this.props.maxLength you never set the actual state, leaving the state.value as ''. It seems you expected it to have been set to the value, but truncated to maxLength. You'll need to add that yourself:

handleChange(event) {
  /* Check if max length has been set. If max length has been
  set make sure the user input is less than max Length, otherwise
  return before updating the text string. */
  if (this.props.maxLength) {
    if (event.target.value.length > this.props.maxLength) {
      // ** Truncate value to maxLength
      this.setState({ value: event.target.value.substr(0, this.props.maxLength) });
      return;
    }
  }
  this.setState({ value: event.target.value });
}

... then, the following test works and passes:

it('Make sure inputted text is shorter than max length', () => {
  const result = mount(<Input maxLength={10}></Input>);
  result.find('input').simulate('change', { target: { value: '1234567890!!!' } });
  expect(result.state().value).to.equal("1234567890");
});

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论