events.js 4.3 KB

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