触发 onInput 处理程序

Triggering onInput handler

想象一个带有 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 的点击,但它没有解决问题。

我怎样才能通过考试?

主要问题是 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 属性在不导致组件重新渲染的情况下发生变化。如果您需要更彻底地测试浏览器交互,您可能需要寻求集成(端到端)测试解决方案。