Skip to content

Commit 799d6ca

Browse files
author
Kent C. Dodds
committed
WIP: add setNativeValue for change event
1 parent 87c2cf8 commit 799d6ca

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/__tests__/events.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const eventTypes = [
3030
},
3131
{
3232
type: 'Focus',
33-
events: ['change', 'input', 'invalid'],
33+
events: ['input', 'invalid'],
3434
elementType: 'input',
3535
},
3636
{
@@ -154,3 +154,14 @@ eventTypes.forEach(({type, events, elementType, init}) => {
154154
})
155155
})
156156
})
157+
158+
test('onChange works', () => {
159+
const spy = jest.fn()
160+
161+
const {container} = render(<input onChange={spy} />)
162+
const input = container.firstChild
163+
fireEvent.change(input, {target: {value: 'c'}})
164+
expect(spy).toHaveBeenCalledTimes(1)
165+
})
166+
167+
/* eslint complexity:0 */

src/index.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import ReactDOM from 'react-dom'
22
import {Simulate} from 'react-dom/test-utils'
3-
import {getQueriesForElement, prettyDOM} from 'dom-testing-library'
3+
import {getQueriesForElement, prettyDOM, fireEvent} from 'dom-testing-library'
44

55
const mountedContainers = new Set()
66

@@ -45,8 +45,34 @@ function cleanupAtContainer(container) {
4545
mountedContainers.delete(container)
4646
}
4747

48+
const originalChange = fireEvent.change
49+
fireEvent.change = function reactChange(node, init) {
50+
if (init && init.target && init.target.hasOwnProperty('value')) {
51+
setNativeValue(node, init.target.value)
52+
}
53+
return originalChange(node, init)
54+
}
55+
56+
// function written after some investigation here:
57+
// https://github.com/facebook/react/issues/10135#issuecomment-401496776
58+
function setNativeValue(element, value) {
59+
const {set: valueSetter} =
60+
Object.getOwnPropertyDescriptor(element, 'value') || {}
61+
const prototype = Object.getPrototypeOf(element)
62+
const {set: prototypeValueSetter} =
63+
Object.getOwnPropertyDescriptor(prototype, 'value') || {}
64+
65+
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
66+
prototypeValueSetter.call(element, value)
67+
} else if (valueSetter) {
68+
valueSetter.call(element, value)
69+
} else {
70+
throw new Error('The given element does not have a value setter')
71+
}
72+
}
73+
4874
// fallback to synthetic events for React events that the DOM doesn't support
49-
const syntheticEvents = ['change', 'select', 'mouseEnter', 'mouseLeave']
75+
const syntheticEvents = ['select', 'mouseEnter', 'mouseLeave']
5076
syntheticEvents.forEach(eventName => {
5177
document.addEventListener(eventName.toLowerCase(), e => {
5278
Simulate[eventName](e.target, e)
@@ -56,3 +82,5 @@ syntheticEvents.forEach(eventName => {
5682
// just re-export everything from dom-testing-library
5783
export * from 'dom-testing-library'
5884
export {render, cleanup}
85+
86+
/* eslint complexity:0, func-name-matching:0 */

0 commit comments

Comments
 (0)