Skip to content

Commit

Permalink
feat(fireEvent): helper to assign target properties to node
Browse files Browse the repository at this point in the history
Specifically this is so the change event can set the value of the node
in a way that works for React (and all other frameworks and
non-frameworks) nicely.

fixes: testing-library/react-testing-library#152
  • Loading branch information
Kent C. Dodds committed Aug 4, 2018
1 parent c07a1ab commit 963e9f6
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/__tests__/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,13 @@ describe(`Aliased Events`, () => {
expect(spy).toHaveBeenCalledTimes(1)
})
})

test('assigns target properties', () => {
const node = document.createElement('input')
const spy = jest.fn()
const value = 'a'
node.addEventListener('change', spy)
fireEvent.change(node, {target: {value}})
expect(spy).toHaveBeenCalledTimes(1)
expect(node.value).toBe(value)
})
24 changes: 24 additions & 0 deletions src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,37 @@ Object.entries(eventMap).forEach(([key, {EventType = Event, defaultInit}]) => {

fireEvent[key] = (node, init) => {
const eventInit = Object.assign({}, defaultInit, init)
const {target: {value, ...targetProperties} = {}} = eventInit
Object.assign(node, targetProperties)
if (value !== undefined) {
setNativeValue(node, value)
}
const event = new EventType(eventName, eventInit)
return fireEvent(node, event)
}
})

// 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')
}
}

Object.entries(eventAliasMap).forEach(([aliasKey, key]) => {
fireEvent[aliasKey] = (...args) => fireEvent[key](...args)
})

export {fireEvent}

/* eslint complexity:["error", 9] */

0 comments on commit 963e9f6

Please sign in to comment.