Understanding Events and plugins


(Kent C. Dodds) #1

I’m looking for some educational content/material to learn more about React’s event plugin system so I can make better testing utilities for React.

I’m in the process of improving react-testing-library and firing events for things like change events, select events, and others which behave differently for React than default browser events. Because react-testing-library is focused on firing actual browser events rather than simulated/synthetic events, this has been a little tricky. For most events it works totally fine. Dispatching a click event on a node is successfully handled by React’s global event handler and calls the event listener on that node. However, the select event is proving to be more difficult considering React doesn’t actually have a listener for the select event and instead relies on other events to simulate that behavior.

From what I gather, a select synthetic event is created when one of the plugin “dependencies” is fired on a node. But I’d like to understand this a little better and perhaps receive input into what a good approach would be for when someone’s trying to test their element’s onSelect handler functionality.

Specifically, I could use some insight into what the properties in this object mean:

const eventTypes = {
  select: {
    phasedRegistrationNames: {
      bubbled: 'onSelect',
      captured: 'onSelectCapture',
    },
    dependencies: [
      TOP_BLUR,
      TOP_CONTEXT_MENU,
      TOP_FOCUS,
      TOP_KEY_DOWN,
      TOP_KEY_UP,
      TOP_MOUSE_DOWN,
      TOP_MOUSE_UP,
      TOP_SELECTION_CHANGE,
    ],
  },
};

On top of that, what browser-based DOM event should react-testing-library fire to achieve the desired result when someone does this in an effort to test their onSelect handler?

myInput.selectionStart = 0
myInput.selectionEnd = 3
fireEvent.select(myInput)

Would that even make sense? Is there a better API for this? Advice is welcome :slight_smile:

As a side-note, there’s some funny things we have to do for the change event, but at the end of it all, the API is actually not too bad:

fireEvent.change(myInput, { target: { value: 'a' } })

Thoughts, feedback, advice, and enlightenment are all welcome. Thanks!