4

Here is the example:

http://jsfiddle.net/hulufei/twr4thuh/7/

It just worked when bind onClick in virtual dom(like line 18), but If I comment line 18 and comment off line 8 to bind click with addEventListener, it failed.

So what's the problem?

James Montagne
  • 77,516
  • 14
  • 110
  • 130
hulufei
  • 737
  • 1
  • 6
  • 17

2 Answers2

2

TestUtils triggers events within react's synthetic event system, so the native event that addEventListener listens for is never going to be triggered. You will need to use the native click method on the element in your test:

    var events = Events();
    ReactTestUtils.renderIntoDocument(events);
    events.refs.button.getDOMNode().click();

    events.state.event.should.equal('click');

Additionally, you've misspelled clickHandler in your addEventListener definition.

jsfiddle

You can also simplify adding your event listener by reusing your prop definition:

componentDidMount: function () {
    this.refs.button.getDOMNode().addEventListener('click', this.clickHandler);
},

Note:

Is there a reason why you want to use addEventListener instead of just passing an onClick attribute for your button? Unless there's a specific and good reason otherwise, i'd suggest doing things the react way when handling events for sanity :)

Edit

I originally mentioned that I did not know what TestUtils' SimulateNative.click did not trigger the event. I was wrong in thinking that it ever would since it would be simulating a native click event within the react even system. @thilo pointed me in the right direction :)

Nick Tomlin
  • 28,402
  • 11
  • 61
  • 90
  • thanks for your answer, it's really helpful to point out react's synthetic event system. I'm a little confused about your last mentioned `SimulateNative.Click`, is that mean `SimulateNative.Click` can trigger native events, instead `Simulate.Click` only triggers events within react's synthetic event system? – hulufei Nov 25 '14 at 02:44
  • About why I use `addEventListener`. I defined a mixin, I wanted to bind some events in mixin instead of manually bind these events in every component using the mixin, and some other events binded dynamically in some triggered event handler. Is there a better way to do this? – hulufei Nov 25 '14 at 02:57
  • @hulufei `SimulateNative` just dispatches a "native" event through react's synthetic event system, rather than a "react" event [source](https://github.com/facebook/react/blob/master/src/test/ReactTestUtils.js#L264). So it's never going to trigger a native event listener. As for an approach to share behavior between components, It's hard to say without seeing what you are trying to accomplish. I would start another SO question. – Nick Tomlin Nov 25 '14 at 17:15
1

I had many problems while testing addEventListener, and I got the following conclusion.

You can create the events listener with pure javascript, jquery, but when running the tests with Jest I always had a problem.

The rendering of ReactTestUtils does not work directly with the document, and when we do:

For example, our events were added in the document, when rendering with ReactTestUtils it creates a div and renders it in the div, This way I could not get Simulate to trigger the call.

My first solution was to use jquery to create the listener and to test I did the render manually by appending the div in document.body, and triggered the events with the dispachEvent of javascript. But I thought the code was dirty, not the best way to work.

I made a sample code by adding the event and testing it with Jest, also have a test teaching to get all the listener that were created.

You can find the code here: https://github.com/LVCarnevalli/create-react-app/tree/master/src/components/datepicker

Component:

componentDidMount() {   
 ReactDOM.findDOMNode(this.datePicker.refs.input).addEventListener("change", (event) => {
    const value = event.target.value;
    this.handleChange(Moment(value).toISOString(), value);
  });
}

Test:

it('change empty value date picker', () => {
    const app = ReactTestUtils.renderIntoDocument(<Datepicker />);
    const datePicker = ReactDOM.findDOMNode(app.datePicker.refs.input);
    const value = "";

    const event = new Event("change");
    datePicker.value = value;
    datePicker.dispatchEvent(event);

    expect(app.state.formattedValue).toEqual(value);
});

Links:

window.addEventListener not triggered by simulated events: https://github.com/airbnb/enzyme/issues/426

Creating and triggering events: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events