140 lines
4.3 KiB
JavaScript
140 lines
4.3 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.createEvent = createEvent;
|
|
exports.fireEvent = fireEvent;
|
|
var _config = require("./config");
|
|
var _helpers = require("./helpers");
|
|
var _eventMap = require("./event-map");
|
|
function fireEvent(element, event) {
|
|
return (0, _config.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 = (0, _helpers.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.eventMap).forEach(key => {
|
|
const {
|
|
EventType,
|
|
defaultInit
|
|
} = _eventMap.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);
|
|
} else {
|
|
/* istanbul ignore if */
|
|
// eslint-disable-next-line no-lonely-if -- Can't be ignored by istanbul otherwise
|
|
if (valueSetter) {
|
|
valueSetter.call(element, value);
|
|
} else {
|
|
throw new Error('The given element does not have a value setter');
|
|
}
|
|
}
|
|
}
|
|
Object.keys(_eventMap.eventAliasMap).forEach(aliasKey => {
|
|
const key = _eventMap.eventAliasMap[aliasKey];
|
|
fireEvent[aliasKey] = (...args) => fireEvent[key](...args);
|
|
});
|
|
|
|
/* eslint complexity:["error", 9] */ |