Skip to content

Commit 8d9c2fa

Browse files
Kent C. Doddsvitalyso
Kent C. Dodds
authored andcommitted
WIP: add setNativeValue for change event
1 parent c96cd4e commit 8d9c2fa

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

src/__tests__/events.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,12 @@ eventTypes.forEach(({type, events, elementType, init}) => {
156156
})
157157

158158
test('onChange works', () => {
159-
const handleChange = jest.fn()
160-
const {
161-
container: {firstChild: input},
162-
} = render(<input onChange={handleChange} />)
163-
fireEvent.change(input, {target: {value: 'a'}})
164-
expect(handleChange).toHaveBeenCalledTimes(1)
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)
165165
})
166+
167+
/* eslint complexity:0 */

src/index.js

Lines changed: 29 additions & 1 deletion
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

@@ -59,6 +59,32 @@ function cleanupAtContainer(container) {
5959
mountedContainers.delete(container)
6060
}
6161

62+
const originalChange = fireEvent.change
63+
fireEvent.change = function reactChange(node, init) {
64+
if (init && init.target && init.target.hasOwnProperty('value')) {
65+
setNativeValue(node, init.target.value)
66+
}
67+
return originalChange(node, init)
68+
}
69+
70+
// function written after some investigation here:
71+
// https://github.com/facebook/react/issues/10135#issuecomment-401496776
72+
function setNativeValue(element, value) {
73+
const {set: valueSetter} =
74+
Object.getOwnPropertyDescriptor(element, 'value') || {}
75+
const prototype = Object.getPrototypeOf(element)
76+
const {set: prototypeValueSetter} =
77+
Object.getOwnPropertyDescriptor(prototype, 'value') || {}
78+
79+
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
80+
prototypeValueSetter.call(element, value)
81+
} else if (valueSetter) {
82+
valueSetter.call(element, value)
83+
} else {
84+
throw new Error('The given element does not have a value setter')
85+
}
86+
}
87+
6288
// fallback to synthetic events for React events that the DOM doesn't support
6389
const syntheticEvents = ['select', 'mouseEnter', 'mouseLeave']
6490
syntheticEvents.forEach(eventName => {
@@ -70,3 +96,5 @@ syntheticEvents.forEach(eventName => {
7096
// just re-export everything from dom-testing-library
7197
export * from 'dom-testing-library'
7298
export {render, cleanup}
99+
100+
/* eslint complexity:0, func-name-matching:0 */

0 commit comments

Comments
 (0)