5

I am writing tests for ReactJS components in karma + PhatomJS. I am rendering the component and using jQuery as a shortcut to target dom elements and simulate user actions. Clicking, text input, etc works fine. However, the selection in a select doesn't seem to execute the component's onChange event. Here's the code:

import React from 'react'
import ReactDOM from 'react-dom'
import $ from 'jquery'

class SelectComponent extends React.Component {
    handleChange (event) {
        // This is NEVER fired
        doSomething()
    }
    render () {
        return (
            <select id='Fruits' onChange={this.handleChange.bind(this)}>
                <option value='A'>Apple</option>
                <option value='B'>Banana</option>
                <option value='C'>Cranberry</option>
            </select>
        )
    }
}

ReactDOM.render(<SelectComponent />, document.createElement('div'))

// Pragmatically change the selection
$('#Fruits').val('B').change()

However, without jQuery, it seems to work just fine. When I change the last line to:

const element = document.getElementById('Fruits')
element.value = value
element.dispatchEvent(new Event('change', { bubbles: true }))

the callback in ReactJS gets fired!

I cannot spot any difference. I thought that the code above is practically the same what jQuery does with .val('B').change(). Perhaps a jQuery ninja can give me a hint on this one?

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
Roman Semko
  • 1,541
  • 5
  • 18
  • 27

1 Answers1

4

It doesn't work with jQuery change() because that doesn't trigger a "real" change event. It's a shortcut for .trigger('change') which says

A call to .trigger() executes the handlers in the same order they would be if the event were triggered naturally by the user

and

Although .trigger() simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.

I believe this was done in order to help support very old versions of IE that had different handling of events.

That's the why of it at any rate, since that's what you wanted to know. Just firing the event natively makes your tests less coupled with your implementation choices.

ivarni
  • 17,658
  • 17
  • 76
  • 92
  • 1
    Is there a way to trigger the "real" 'change' event with jQuery? I know, it's another question. But wondering if you know a solution. ^^ – Roman Semko Jul 21 '16 at 06:29
  • @RomanSemko I've been avoiding jQuery since we dropped IE8 support two years ago so I'm afraid I wouldn't know :) – ivarni Jul 21 '16 at 06:36
  • 2
    @RomanSemko A quick google search came up with [this](http://stackoverflow.com/a/21292403/957731) but it basically just wraps creating a native event into a plugin. Which might be exactly what you need to do unless something's been changed in v3.0 – ivarni Jul 21 '16 at 06:38
  • BTW, that question might serve as a duplicate of yours. I think the answer I linked is better than mine. – ivarni Jul 21 '16 at 06:39