events.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.createEvent = createEvent;
  6. exports.fireEvent = fireEvent;
  7. var _config = require("./config");
  8. var _helpers = require("./helpers");
  9. var _eventMap = require("./event-map");
  10. function fireEvent(element, event) {
  11. return (0, _config.getConfig)().eventWrapper(() => {
  12. if (!event) {
  13. throw new Error(`Unable to fire an event - please provide an event object.`);
  14. }
  15. if (!element) {
  16. throw new Error(`Unable to fire a "${event.type}" event - please provide a DOM element.`);
  17. }
  18. return element.dispatchEvent(event);
  19. });
  20. }
  21. function createEvent(eventName, node, init, {
  22. EventType = 'Event',
  23. defaultInit = {}
  24. } = {}) {
  25. if (!node) {
  26. throw new Error(`Unable to fire a "${eventName}" event - please provide a DOM element.`);
  27. }
  28. const eventInit = {
  29. ...defaultInit,
  30. ...init
  31. };
  32. const {
  33. target: {
  34. value,
  35. files,
  36. ...targetProperties
  37. } = {}
  38. } = eventInit;
  39. if (value !== undefined) {
  40. setNativeValue(node, value);
  41. }
  42. if (files !== undefined) {
  43. // input.files is a read-only property so this is not allowed:
  44. // input.files = [file]
  45. // so we have to use this workaround to set the property
  46. Object.defineProperty(node, 'files', {
  47. configurable: true,
  48. enumerable: true,
  49. writable: true,
  50. value: files
  51. });
  52. }
  53. Object.assign(node, targetProperties);
  54. const window = (0, _helpers.getWindowFromNode)(node);
  55. const EventConstructor = window[EventType] || window.Event;
  56. let event;
  57. /* istanbul ignore else */
  58. if (typeof EventConstructor === 'function') {
  59. event = new EventConstructor(eventName, eventInit);
  60. } else {
  61. // IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
  62. event = window.document.createEvent(EventType);
  63. const {
  64. bubbles,
  65. cancelable,
  66. detail,
  67. ...otherInit
  68. } = eventInit;
  69. event.initEvent(eventName, bubbles, cancelable, detail);
  70. Object.keys(otherInit).forEach(eventKey => {
  71. event[eventKey] = otherInit[eventKey];
  72. });
  73. }
  74. // DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568
  75. const dataTransferProperties = ['dataTransfer', 'clipboardData'];
  76. dataTransferProperties.forEach(dataTransferKey => {
  77. const dataTransferValue = eventInit[dataTransferKey];
  78. if (typeof dataTransferValue === 'object') {
  79. /* istanbul ignore if */
  80. if (typeof window.DataTransfer === 'function') {
  81. Object.defineProperty(event, dataTransferKey, {
  82. value: Object.getOwnPropertyNames(dataTransferValue).reduce((acc, propName) => {
  83. Object.defineProperty(acc, propName, {
  84. value: dataTransferValue[propName]
  85. });
  86. return acc;
  87. }, new window.DataTransfer())
  88. });
  89. } else {
  90. Object.defineProperty(event, dataTransferKey, {
  91. value: dataTransferValue
  92. });
  93. }
  94. }
  95. });
  96. return event;
  97. }
  98. Object.keys(_eventMap.eventMap).forEach(key => {
  99. const {
  100. EventType,
  101. defaultInit
  102. } = _eventMap.eventMap[key];
  103. const eventName = key.toLowerCase();
  104. createEvent[key] = (node, init) => createEvent(eventName, node, init, {
  105. EventType,
  106. defaultInit
  107. });
  108. fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init));
  109. });
  110. // function written after some investigation here:
  111. // https://github.com/facebook/react/issues/10135#issuecomment-401496776
  112. function setNativeValue(element, value) {
  113. const {
  114. set: valueSetter
  115. } = Object.getOwnPropertyDescriptor(element, 'value') || {};
  116. const prototype = Object.getPrototypeOf(element);
  117. const {
  118. set: prototypeValueSetter
  119. } = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
  120. if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
  121. prototypeValueSetter.call(element, value);
  122. } else {
  123. /* istanbul ignore if */
  124. // eslint-disable-next-line no-lonely-if -- Can't be ignored by istanbul otherwise
  125. if (valueSetter) {
  126. valueSetter.call(element, value);
  127. } else {
  128. throw new Error('The given element does not have a value setter');
  129. }
  130. }
  131. }
  132. Object.keys(_eventMap.eventAliasMap).forEach(aliasKey => {
  133. const key = _eventMap.eventAliasMap[aliasKey];
  134. fireEvent[aliasKey] = (...args) => fireEvent[key](...args);
  135. });
  136. /* eslint complexity:["error", 9] */