diff --git a/src/__tests__/events.js b/src/__tests__/events.js index 679412e8..985183c0 100644 --- a/src/__tests__/events.js +++ b/src/__tests__/events.js @@ -30,7 +30,7 @@ const eventTypes = [ }, { type: 'Focus', - events: ['change', 'input', 'invalid'], + events: ['input', 'invalid'], elementType: 'input', }, { @@ -154,3 +154,14 @@ eventTypes.forEach(({type, events, elementType, init}) => { }) }) }) + +test('onChange works', () => { + const spy = jest.fn() + + const {container} = render() + const input = container.firstChild + fireEvent.change(input, {target: {value: 'c'}}) + expect(spy).toHaveBeenCalledTimes(1) +}) + +/* eslint complexity:0 */ diff --git a/src/index.js b/src/index.js index 8993e012..c9ac25f3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ import ReactDOM from 'react-dom' import {Simulate} from 'react-dom/test-utils' -import {getQueriesForElement, prettyDOM} from 'dom-testing-library' +import {getQueriesForElement, prettyDOM, fireEvent} from 'dom-testing-library' const mountedContainers = new Set() @@ -45,8 +45,34 @@ function cleanupAtContainer(container) { mountedContainers.delete(container) } +const originalChange = fireEvent.change +fireEvent.change = function reactChange(node, init) { + if (init && init.target && init.target.hasOwnProperty('value')) { + setNativeValue(node, init.target.value) + } + return originalChange(node, init) +} + +// function written after some investigation here: +// https://github.com/facebook/react/issues/10135#issuecomment-401496776 +function setNativeValue(element, value) { + const {set: valueSetter} = + Object.getOwnPropertyDescriptor(element, 'value') || {} + const prototype = Object.getPrototypeOf(element) + const {set: prototypeValueSetter} = + Object.getOwnPropertyDescriptor(prototype, 'value') || {} + + if (prototypeValueSetter && valueSetter !== prototypeValueSetter) { + prototypeValueSetter.call(element, value) + } else if (valueSetter) { + valueSetter.call(element, value) + } else { + throw new Error('The given element does not have a value setter') + } +} + // fallback to synthetic events for React events that the DOM doesn't support -const syntheticEvents = ['change', 'select', 'mouseEnter', 'mouseLeave'] +const syntheticEvents = ['select', 'mouseEnter', 'mouseLeave'] syntheticEvents.forEach(eventName => { document.addEventListener(eventName.toLowerCase(), e => { Simulate[eventName](e.target, e) @@ -56,3 +82,5 @@ syntheticEvents.forEach(eventName => { // just re-export everything from dom-testing-library export * from 'dom-testing-library' export {render, cleanup} + +/* eslint complexity:0, func-name-matching:0 */