【问题标题】:What is a good way of testing React component callbacks to parent components?测试 React 组件回调到父组件的好方法是什么?
【发布时间】:2016-05-31 04:52:29
【问题描述】:

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

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

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

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

示例

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

Repo with the complete example.

假设我有一个接受文本输入并在提交时通过 props 传递的组件:

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

});

【问题讨论】:

    标签: javascript testing meteor reactjs


    【解决方案1】:

    一种不需要父组件的方法是使用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);
      });
    
    });
    

    【讨论】:

    • 这是一个显着的改进。谢谢!另外,感谢您提供 findRenderedDOMComponentWithTag 的示例,我也将开始使用它。 (我使用此解决方案更新了上面的存储库。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多