-
Notifications
You must be signed in to change notification settings - Fork 472
/
Copy pathevents.js
128 lines (117 loc) · 4.06 KB
/
events.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import {getConfig} from './config'
import {getWindowFromNode} from './helpers'
import {eventMap, eventAliasMap} from './event-map'
function fireEvent(element, event) {
return getConfig().eventWrapper(() => {
if (!event) {
throw new Error(
`Unable to fire an event - please provide an event object.`,
)
}
if (!element) {
throw new Error(
`Unable to fire a "${event.type}" event - please provide a DOM element.`,
)
}
return element.dispatchEvent(event)
})
}
function createEvent(
eventName,
node,
init,
{EventType = 'Event', defaultInit = {}} = {},
) {
if (!node) {
throw new Error(
`Unable to fire a "${eventName}" event - please provide a DOM element.`,
)
}
const eventInit = {...defaultInit, ...init}
const {target: {value, files, ...targetProperties} = {}} = eventInit
if (value !== undefined) {
setNativeValue(node, value)
}
if (files !== undefined) {
// input.files is a read-only property so this is not allowed:
// input.files = [file]
// so we have to use this workaround to set the property
Object.defineProperty(node, 'files', {
configurable: true,
enumerable: true,
writable: true,
value: files,
})
}
Object.assign(node, targetProperties)
const window = getWindowFromNode(node)
const EventConstructor = window[EventType] || window.Event
let event
/* istanbul ignore else */
if (typeof EventConstructor === 'function') {
event = new EventConstructor(eventName, eventInit)
} else {
// IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
event = window.document.createEvent(EventType)
const {bubbles, cancelable, detail, ...otherInit} = eventInit
event.initEvent(eventName, bubbles, cancelable, detail)
Object.keys(otherInit).forEach(eventKey => {
event[eventKey] = otherInit[eventKey]
})
}
// DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568
const dataTransferProperties = ['dataTransfer', 'clipboardData']
dataTransferProperties.forEach(dataTransferKey => {
const dataTransferValue = eventInit[dataTransferKey]
if (typeof dataTransferValue === 'object') {
/* istanbul ignore if */
if (typeof window.DataTransfer === 'function') {
Object.defineProperty(event, dataTransferKey, {
value: Object.getOwnPropertyNames(dataTransferValue).reduce(
(acc, propName) => {
Object.defineProperty(acc, propName, {
value: dataTransferValue[propName],
})
return acc
},
new window.DataTransfer(),
),
})
} else {
Object.defineProperty(event, dataTransferKey, {
value: dataTransferValue,
})
}
}
})
return event
}
Object.keys(eventMap).forEach(key => {
const {EventType, defaultInit} = eventMap[key]
const eventName = key.toLowerCase()
createEvent[key] = (node, init) =>
createEvent(eventName, node, init, {EventType, defaultInit})
fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](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)
} /* istanbul ignore next (I don't want to bother) */ else if (valueSetter) {
valueSetter.call(element, value)
} else {
throw new Error('The given element does not have a value setter')
}
}
Object.keys(eventAliasMap).forEach(aliasKey => {
const key = eventAliasMap[aliasKey]
fireEvent[aliasKey] = (...args) => fireEvent[key](...args)
})
export {fireEvent, createEvent}
/* eslint complexity:["error", 9] */