测试React组件回调到父组件的好方法是什么?

时间:2016-02-18 20:05:02

标签: javascript testing meteor reactjs

我目前正在采用更多的TDD方法,并希望在测试React组件方面做得更好。测试我正在努力解决的React组件的一个方面是测试子组件对父组件的回调。

测试内部React组件通信的有效方法是什么,例如回调父组件?

this question的回复似乎提供了一种可能的解决方案,但我并不十分理解它(例如,我并不完全熟悉如何在Jasmine测试中使用函数链。)

提前感谢任何提示和建议!

示例

(以下示例使用Meteor,但我不一定要寻找特定于Meteor的解决方案。)

Repo with the complete example

我们说我有一个接受文字输入的组件,并通过提交上的道具传递它:

SingleFieldSubmit = React.createClass({
  propTypes: {
    handleInput: React.PropTypes.func.isRequired
  },
  getDefaultProps() {
    return {
      inputValue:  ""
    };
  },
  getInitialState() {
    return {
      inputValue: this.props.inputValue
    };
  },
  updateInputValue(e){
    this.setState({inputValue: e.target.value});
  },
  handleSubmit(e) {
    e.preventDefault();
    this.handleInput();
  },
  handleInput(){
    this.props.handleInput(this.state.inputValue.trim());
  },
  render() {
    return (
      <form className="single-field-submit" onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.inputValue}
          onChange={this.updateInputValue}
        />
      </form>
    )
  }
});

在这里,我想测试组件是否在提交时传递用户输入。我目前有点笨重的解决方案是创建一个模拟父组件,我要测试的组件包含在子项中:

MockParentComponent = React.createClass({
  getInitialState: function() {
    return {
      callbackValue: null
    };
  },
  handleCallback: function(value) {
    this.setState({callbackValue: value});
  },
  render: function() {
    return (
      <div className="container">
        <SingleFieldSubmit handleInput={this.handleCallback} />
      </div>
    )
  }
});

然后,我的(Jasmine)测试看起来像这样。测试通过。但是,似乎应该有一种更简单的方法来做到这一点....

describe('SingleFieldSubmit Component', function () {

  it('should, on submit, return the value input into the form', function () {

    //SETUP
    let mockUserInput = 'Test input';
    let parentComponent = TestUtils.renderIntoDocument(
          React.createElement(MockParentComponent)
          );
    let node     = ReactDOM.findDOMNode(parentComponent);
    let $node    = $(node);
    expect(parentComponent.state.callbackValue).toBe(null);

    //TEST
    Simulate.change($node.find('input')[0], { target: { value: mockUserInput } });
    Simulate.submit($node.find('form')[0]);
    expect(parentComponent.state.callbackValue).toBe(mockUserInput);
  });

});

1 个答案:

答案 0 :(得分:6)

一个不需要父组件的方法是使用jasmine spies

describe('SingleFieldSubmit Component', function () {

  it('should call handleInput prop with value of the input on submit', function () {

    //SETUP
    let callbackSpy = jasmine.createSpy('callbackSpy');
    let mockUserInput = 'Test input';
    let component = TestUtils.renderIntoDocument(<SingleFieldSubmit handleInput={callbackSpy} />);
    let form = TestUtils.findRenderedDOMComponentWithTag(component, 'form');
    let input = TestUtils.findRenderedDOMComponentWithTag(component, 'input')

    //TEST
    Simulate.change(imput, { target: { value: mockUserInput } });
    Simulate.submit(form);
    expect(callbackSpy).toHaveBeenCalledWith(mockUserInput);
    expect(callbackSpy.calls.count()).toEqual(1);
  });

});