触发onInput处理程序

时间:2015-11-29 13:11:02

标签: javascript javascript-events reactjs contenteditable

想象一个带有oninput事件监听器的简单contentEditable组件。

export default React.createClass({
  render() {
    return React.createElement('p', {
      contentEditable: true,
      onInput: this.emitChange
    });
  },

  emitChange(e) {
    console.log("Input event occurred", e);
  }
});

在我的测试中,我模拟了组件上的input事件(例如用户在contentEditable标记中键入字母' a')。

这适用于浏览器,我可以点击该组件,按下' a'钥匙,我会看到一个' a'在标记中,console.log将触发。我无法让它在这个测试中工作:

// Require the code from the block above.
var CE = require('content-editable');

describe('Component', function() {
  it('updates state when we type', function() {
    // Render a component instance and get a handle on it.
    let ce = TestUtils.renderIntoDocument(<CE/>);
    let _ce = ReactDOM.findDOMNode(ce);

    TestUtils.Simulate.input(_ce, {
      key: 'a'
    });

    expect(_ce.textContent).to.equal('a');
  });
});

此测试失败,因为_ce.textContent是一个空字符串。我已经尝试在模拟输入之前模拟_ce上的点击,但它并没有解决问题。

如何通过测试?

1 个答案:

答案 0 :(得分:2)

主要问题是TestUtils.Simulate实际上并没有向DOM发送事件,它会创建一个虚假事件并通过React的事件处理系统发送它。您可以通过回调将更改事件传播回父组件来缓解此问题,您可能还需要执行此操作来检索可编辑的值:

export default React.createClass({
  propTypes: {
    onChange: React.PropTypes.func
  },

  render() {
    return React.createElement('p', {
      contentEditable: true,
      onInput: this.emitChange
    });
  },

  emitChange(e) {
    if (this.props.onChange) {
      this.props.onChange(e);
    }
  }
});

现在我们可以测试是否调用了onChange:

describe('Component', function() {
  it('updates state when we type', function() {
    let changeFired = false;
    let ce = TestUtils.renderIntoDocument(<CE onChange={verify} />);
    let _ce = ReactDOM.findDOMNode(ce);

    TestUtils.Simulate.input(_ce, {
      key: 'a'
    });

    function verify(e) {
      changeFired = true;
      expect(e.key).to.equal('a');
    }

    expect(changeFired).to.equal(true);
  });
});

这将对emitChange函数中的代码进行单元测试,而不与环境的其他部分进行任何实际交互。这可能是您在单元测试中所需要的,因为当用户键入一个键时,您的组件并不关心浏览器对DOM的作用,它关心的是它能够在浏览器告诉它时执行某些操作事情发生了。

通常在React单元测试中,您不会看到textContentinnerHTML DOM属性发生更改,而不会导致组件重新呈现。如果您需要更彻底地测试浏览器交互,则可能需要采用集成(端到端)测试解决方案。