2

I have a component that uses contentEditable as an input method. The part from the component that is of interest is:

<div className="enter-edit-mode" onClick={view.enterEditMode}>
    <div className="user-input" ref="content" contentEditable onInput={view.textChanged}></div>
</div>

The component works fine - it gets into the textChanged method on user input. The method looks like this:

textChanged: function (e) {
    var view      = this,
        textValue = e.target.innerHTML;

    view.setState({
        enteringText: textValue.length,
        temporaryValue: textValue
    });
}

The problem I'm facing appears when I try to test the input behavior. The setup is done with enzyme, chai, sinon. I'm rendering the component using a simple renderComponent function, using enzyme's mount method.

beforeEach(function () {
    view = renderComponent(card);
    viewReact = view.get(0);
});

it('should enter text changed method on input', function () {
    let spy = sinon.spy(viewReact, 'textChanged');
    view.find('.user-input').simulate('input');
    expect(spy).to.have.been.called;
    spy.restore();
});

It outputs expected textChanged to have been called at least once, but it was never called. The weird part is, however, if I put a console.log inside the component's method, it gets there.

What I've tried to make it work

  • use sinon.stub instead of spy, as I though that maybe something in my method doesn't work properly
  • call it with view.find('.user-input').simulate('input', {target: {value: "lorem"}) or .simulate('input', {key: 'a'})

If instead of simulating the input I do a viewReact.textChanged(), it obviously works.

I'm guessing that it's the input method on contentEditable that's causing this. Any suggestions? How can I properly enter text in the onInput method? (even if it gets in the textChanged method, the text is empty)

4

2 回答 2

1

我可以重现您的问题,尝试测试以下组件(看起来与您的类似):

const MyComponent = React.createClass({
  textChanged(e) { console.log('text changed') },
  render() {
    return (
      <div className="enter-edit-mode">
        <div className="user-input" ref="content" contentEditable onInput={ this.textChanged }></div>
      </div>
    );
  }
});

我还设法让测试以一种有点复杂的方式工作:

it('should enter text changed method on input', () => {
  let view = mount(<MyComponent/>);
  let spy  = sinon.spy(view.instance(), 'textChanged');
  view     = view.mount();

  view.find('.user-input').simulate('input');
  expect(spy).to.be.called;
  spy.restore();
});

view.mount()重新安装组件似乎在这里起到了作用。

我对Enzyme一点都不熟悉(虽然我喜欢它:),但它看起来像是在组件周围添加了各种层,这样一来诗浓间谍很容易“迷路”。

一个可能的警告:我在 Node 中使用jsdom而不是在浏览器中进行了所有这些测试。

于 2016-06-02T20:10:03.400 回答
0

我做了一个小测试,我没有 sinon 但我找到了一个用例:

class Home extends Component {

  state = {
    status: 'default'
  }

  textChanged = () => {
    this.setState({
      status: 'changed'
    })
  }

  render () {
    return (
        <div className="enter-edit-mode" >
          <div className="user-input" ref="content" contentEditable onInput={this.textChanged}>Hello</div>
          <span>{this.state.status}</span>
        </div>
    )
  }
}

和测试

describe('component', () => {
    it('should say changed', () => {
      const component = shallow(<Home />);

      expect(component.find('span').text()).toEqual('default');

      component.find('.user-input').simulate('input', {key: 'a'})

      expect(component.find('span').text()).toEqual('changed');
    });
});

它通过了所有预期

于 2016-06-02T15:53:52.263 回答