@samitouri / QOS-React-2 / commits / 91c9d69f9a

Modern Event System: Remove TestUtils.SimulateNative support (#18471)

Dominic Gannaway committed Apr 3, 2020 at 00:12 UTC 91c9d69f9aff710ba2b113834386b0bf01aea742
6 files changed +329 -334
packages/react-dom/src/__tests__/ReactTestUtils-test.js
+92 -18
@@ -15,6 +15,8 @@ import * as ReactDOM from 'react-dom';
15 import * as ReactDOMServer from 'react-dom/server';
16 import * as ReactTestUtils from 'react-dom/test-utils';
17
18 +const ReactFeatureFlags = require('shared/ReactFeatureFlags');
19 +
20 function getTestDocument(markup) {
21 const doc = document.implementation.createHTMLDocument('');
22 doc.open();
@@ -31,25 +33,97 @@ describe('ReactTestUtils', () => {
33 expect(Object.keys(ReactTestUtils.Simulate).sort()).toMatchSnapshot();
34 });
35
34 - it('SimulateNative should have locally attached media events', () => {
35 - expect(Object.keys(ReactTestUtils.SimulateNative).sort()).toMatchSnapshot();
36 - });
36 + if (!ReactFeatureFlags.enableModernEventSystem) {
37 + // SimulateNative API has been removed in the modern event system
38 + it('SimulateNative should have locally attached media events', () => {
39 + expect(Object.keys(ReactTestUtils.SimulateNative).sort()).toEqual([
40 + 'abort',
41 + 'animationEnd',
42 + 'animationIteration',
43 + 'animationStart',
44 + 'blur',
45 + 'canPlay',
46 + 'canPlayThrough',
47 + 'cancel',
48 + 'change',
49 + 'click',
50 + 'close',
51 + 'compositionEnd',
52 + 'compositionStart',
53 + 'compositionUpdate',
54 + 'contextMenu',
55 + 'copy',
56 + 'cut',
57 + 'doubleClick',
58 + 'drag',
59 + 'dragEnd',
60 + 'dragEnter',
61 + 'dragExit',
62 + 'dragLeave',
63 + 'dragOver',
64 + 'dragStart',
65 + 'drop',
66 + 'durationChange',
67 + 'emptied',
68 + 'encrypted',
69 + 'ended',
70 + 'error',
71 + 'focus',
72 + 'input',
73 + 'keyDown',
74 + 'keyPress',
75 + 'keyUp',
76 + 'load',
77 + 'loadStart',
78 + 'loadedData',
79 + 'loadedMetadata',
80 + 'mouseDown',
81 + 'mouseMove',
82 + 'mouseOut',
83 + 'mouseOver',
84 + 'mouseUp',
85 + 'paste',
86 + 'pause',
87 + 'play',
88 + 'playing',
89 + 'progress',
90 + 'rateChange',
91 + 'scroll',
92 + 'seeked',
93 + 'seeking',
94 + 'selectionChange',
95 + 'stalled',
96 + 'suspend',
97 + 'textInput',
98 + 'timeUpdate',
99 + 'toggle',
100 + 'touchCancel',
101 + 'touchEnd',
102 + 'touchMove',
103 + 'touchStart',
104 + 'transitionEnd',
105 + 'volumeChange',
106 + 'waiting',
107 + 'wheel',
108 + ]);
109 + });
110
38 - it('SimulateNative should warn about deprecation', () => {
39 - const container = document.createElement('div');
40 - const node = ReactDOM.render(<div />, container);
41 - expect(() =>
42 - ReactTestUtils.SimulateNative.click(node),
43 - ).toWarnDev(
44 - 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
45 - 'how the browser dispatches events, and will be removed in a future major ' +
46 - 'version of React. If you rely on it for testing, consider attaching the root ' +
47 - 'DOM container to the document during the test, and then dispatching native browser ' +
48 - 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
49 - 'the `bubbles` flag to `true` when creating the native browser event.',
50 - {withoutStack: true},
51 - );
52 - });
111 + it('SimulateNative should warn about deprecation', () => {
112 + const container = document.createElement('div');
113 + const node = ReactDOM.render(<div />, container);
114 + expect(() =>
115 + ReactTestUtils.SimulateNative.click(node),
116 + ).toWarnDev(
117 + 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
118 + 'how the browser dispatches events, and will be removed in a future major ' +
119 + 'version of React. If you rely on it for testing, consider attaching the root ' +
120 + 'DOM container to the document during the test, and then dispatching native browser ' +
121 + 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
122 + 'the `bubbles` flag to `true` when creating the native browser event.',
123 + {withoutStack: true},
124 + );
125 + });
126 + }
127
128 it('gives Jest mocks a passthrough implementation with mockComponent()', () => {
129 class MockedComponent extends React.Component {
packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap
-73
@@ -88,76 +88,3 @@ Array [
88 "wheel",
89 ]
90 `;
91 -
92 -exports[`ReactTestUtils SimulateNative should have locally attached media events 1`] = `
93 -Array [
94 - "abort",
95 - "animationEnd",
96 - "animationIteration",
97 - "animationStart",
98 - "blur",
99 - "canPlay",
100 - "canPlayThrough",
101 - "cancel",
102 - "change",
103 - "click",
104 - "close",
105 - "compositionEnd",
106 - "compositionStart",
107 - "compositionUpdate",
108 - "contextMenu",
109 - "copy",
110 - "cut",
111 - "doubleClick",
112 - "drag",
113 - "dragEnd",
114 - "dragEnter",
115 - "dragExit",
116 - "dragLeave",
117 - "dragOver",
118 - "dragStart",
119 - "drop",
120 - "durationChange",
121 - "emptied",
122 - "encrypted",
123 - "ended",
124 - "error",
125 - "focus",
126 - "input",
127 - "keyDown",
128 - "keyPress",
129 - "keyUp",
130 - "load",
131 - "loadStart",
132 - "loadedData",
133 - "loadedMetadata",
134 - "mouseDown",
135 - "mouseMove",
136 - "mouseOut",
137 - "mouseOver",
138 - "mouseUp",
139 - "paste",
140 - "pause",
141 - "play",
142 - "playing",
143 - "progress",
144 - "rateChange",
145 - "scroll",
146 - "seeked",
147 - "seeking",
148 - "selectionChange",
149 - "stalled",
150 - "suspend",
151 - "textInput",
152 - "timeUpdate",
153 - "toggle",
154 - "touchCancel",
155 - "touchEnd",
156 - "touchMove",
157 - "touchStart",
158 - "transitionEnd",
159 - "volumeChange",
160 - "waiting",
161 - "wheel",
162 -]
163 -`;
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+70 -75
@@ -218,7 +218,7 @@ function dispatchEventsForPlugins(
218 eventSystemFlags: EventSystemFlags,
219 nativeEvent: AnyNativeEvent,
220 targetInst: null | Fiber,
221 - targetContainer: null | EventTarget,
221 + targetContainer: EventTarget,
222 ): void {
223 const nativeEventTarget = getEventTarget(nativeEvent);
224 const syntheticEvents: Array<ReactSyntheticEvent> = [];
@@ -395,90 +395,85 @@ export function dispatchEventForPluginEventSystem(
395 eventSystemFlags: EventSystemFlags,
396 nativeEvent: AnyNativeEvent,
397 targetInst: null | Fiber,
398 - targetContainer: null | EventTarget,
398 + targetContainer: EventTarget,
399 ): void {
400 let ancestorInst = targetInst;
401 - if (targetContainer !== null) {
402 - if (eventSystemFlags & IS_TARGET_PHASE_ONLY) {
403 - // For TargetEvent nodes (i.e. document, window)
404 - ancestorInst = null;
405 - } else {
406 - const targetContainerNode = ((targetContainer: any): Node);
407 -
408 - // If we are using the legacy FB support flag, we
409 - // defer the event to the null with a one
410 - // time event listener so we can defer the event.
411 - if (
412 - enableLegacyFBSupport &&
413 - // We do not want to defer if the event system has already been
414 - // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when
415 - // we call willDeferLaterForLegacyFBSupport, thus not bailing out
416 - // will result in endless cycles like an infinite loop.
417 - (eventSystemFlags & LEGACY_FB_SUPPORT) === 0 &&
418 - // We also don't want to defer during event replaying.
419 - (eventSystemFlags & IS_REPLAYED) === 0 &&
420 - // We don't want to apply the legacy FB support for the useEvent API.
421 - (eventSystemFlags & USE_EVENT_SYSTEM) === 0 &&
422 - willDeferLaterForLegacyFBSupport(topLevelType, targetContainer)
423 - ) {
424 - return;
425 - }
426 - if (targetInst !== null) {
427 - // The below logic attempts to work out if we need to change
428 - // the target fiber to a different ancestor. We had similar logic
429 - // in the legacy event system, except the big difference between
430 - // systems is that the modern event system now has an event listener
431 - // attached to each React Root and React Portal Root. Together,
432 - // the DOM nodes representing these roots are the "rootContainer".
433 - // To figure out which ancestor instance we should use, we traverse
434 - // up the fiber tree from the target instance and attempt to find
435 - // root boundaries that match that of our current "rootContainer".
436 - // If we find that "rootContainer", we find the parent fiber
437 - // sub-tree for that root and make that our ancestor instance.
438 - let node = targetInst;
439 -
440 - while (true) {
441 - if (node === null) {
442 - return;
401 + if (eventSystemFlags & IS_TARGET_PHASE_ONLY) {
402 + // For TargetEvent nodes (i.e. document, window)
403 + ancestorInst = null;
404 + } else {
405 + const targetContainerNode = ((targetContainer: any): Node);
406 +
407 + // If we are using the legacy FB support flag, we
408 + // defer the event to the null with a one
409 + // time event listener so we can defer the event.
410 + if (
411 + enableLegacyFBSupport &&
412 + // We do not want to defer if the event system has already been
413 + // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when
414 + // we call willDeferLaterForLegacyFBSupport, thus not bailing out
415 + // will result in endless cycles like an infinite loop.
416 + (eventSystemFlags & LEGACY_FB_SUPPORT) === 0 &&
417 + // We also don't want to defer during event replaying.
418 + (eventSystemFlags & IS_REPLAYED) === 0 &&
419 + // We don't want to apply the legacy FB support for the useEvent API.
420 + (eventSystemFlags & USE_EVENT_SYSTEM) === 0 &&
421 + willDeferLaterForLegacyFBSupport(topLevelType, targetContainer)
422 + ) {
423 + return;
424 + }
425 + if (targetInst !== null) {
426 + // The below logic attempts to work out if we need to change
427 + // the target fiber to a different ancestor. We had similar logic
428 + // in the legacy event system, except the big difference between
429 + // systems is that the modern event system now has an event listener
430 + // attached to each React Root and React Portal Root. Together,
431 + // the DOM nodes representing these roots are the "rootContainer".
432 + // To figure out which ancestor instance we should use, we traverse
433 + // up the fiber tree from the target instance and attempt to find
434 + // root boundaries that match that of our current "rootContainer".
435 + // If we find that "rootContainer", we find the parent fiber
436 + // sub-tree for that root and make that our ancestor instance.
437 + let node = targetInst;
438 +
439 + while (true) {
440 + if (node === null) {
441 + return;
442 + }
443 + if (node.tag === HostRoot || node.tag === HostPortal) {
444 + const container = node.stateNode.containerInfo;
445 + if (isMatchingRootContainer(container, targetContainerNode)) {
446 + break;
447 }
444 - if (node.tag === HostRoot || node.tag === HostPortal) {
445 - const container = node.stateNode.containerInfo;
446 - if (isMatchingRootContainer(container, targetContainerNode)) {
447 - break;
448 - }
449 - if (node.tag === HostPortal) {
450 - // The target is a portal, but it's not the rootContainer we're looking for.
451 - // Normally portals handle their own events all the way down to the root.
452 - // So we should be able to stop now. However, we don't know if this portal
453 - // was part of *our* root.
454 - let grandNode = node.return;
455 - while (grandNode !== null) {
448 + if (node.tag === HostPortal) {
449 + // The target is a portal, but it's not the rootContainer we're looking for.
450 + // Normally portals handle their own events all the way down to the root.
451 + // So we should be able to stop now. However, we don't know if this portal
452 + // was part of *our* root.
453 + let grandNode = node.return;
454 + while (grandNode !== null) {
455 + if (grandNode.tag === HostRoot || grandNode.tag === HostPortal) {
456 + const grandContainer = grandNode.stateNode.containerInfo;
457 if (
457 - grandNode.tag === HostRoot ||
458 - grandNode.tag === HostPortal
458 + isMatchingRootContainer(grandContainer, targetContainerNode)
459 ) {
460 - const grandContainer = grandNode.stateNode.containerInfo;
461 - if (
462 - isMatchingRootContainer(grandContainer, targetContainerNode)
463 - ) {
464 - // This is the rootContainer we're looking for and we found it as
465 - // a parent of the Portal. That means we can ignore it because the
466 - // Portal will bubble through to us.
467 - return;
468 - }
460 + // This is the rootContainer we're looking for and we found it as
461 + // a parent of the Portal. That means we can ignore it because the
462 + // Portal will bubble through to us.
463 + return;
464 }
470 - grandNode = grandNode.return;
465 }
466 + grandNode = grandNode.return;
467 }
473 - const parentSubtreeInst = getClosestInstanceFromNode(container);
474 - if (parentSubtreeInst === null) {
475 - return;
476 - }
477 - node = ancestorInst = parentSubtreeInst;
478 - continue;
468 }
480 - node = node.return;
469 + const parentSubtreeInst = getClosestInstanceFromNode(container);
470 + if (parentSubtreeInst === null) {
471 + return;
472 + }
473 + node = ancestorInst = parentSubtreeInst;
474 + continue;
475 }
476 + node = node.return;
477 }
478 }
479 }
packages/react-dom/src/events/ReactDOMEventListener.js
+2 -12
@@ -165,16 +165,6 @@ export function addTrappedEventListener(
165 targetContainer,
166 );
167
168 - // When the targetContainer is null, it means that the container
169 - // target is null, but really we need a real DOM node to attach to.
170 - // In this case, we fallback to the "document" node, but leave the
171 - // targetContainer (which is bound in the above function) to null.
172 - // Really, this only happens for TestUtils.Simulate, so when we
173 - // remove that support, we can remove this block of code.
174 - if (targetContainer === null) {
175 - targetContainer = document;
176 - }
177 -
168 targetContainer =
169 enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport
170 ? (targetContainer: any).ownerDocument
@@ -299,7 +289,7 @@ function dispatchUserBlockingUpdate(
289 export function dispatchEvent(
290 topLevelType: DOMTopLevelEventType,
291 eventSystemFlags: EventSystemFlags,
302 - targetContainer: null | EventTarget,
292 + targetContainer: EventTarget,
293 nativeEvent: AnyNativeEvent,
294 ): void {
295 if (!_enabled) {
@@ -415,7 +405,7 @@ export function dispatchEvent(
405 export function attemptToDispatchEvent(
406 topLevelType: DOMTopLevelEventType,
407 eventSystemFlags: EventSystemFlags,
418 - targetContainer: EventTarget | null,
408 + targetContainer: EventTarget,
409 nativeEvent: AnyNativeEvent,
410 ): null | Container | SuspenseInstance {
411 // TODO: Warn if _enabled is false.
packages/react-dom/src/events/ReactDOMEventReplaying.js
+5 -5
@@ -291,7 +291,7 @@ function createQueuedReplayableEvent(
291 blockedOn: null | Container | SuspenseInstance,
292 topLevelType: DOMTopLevelEventType,
293 eventSystemFlags: EventSystemFlags,
294 - targetContainer: EventTarget | null,
294 + targetContainer: EventTarget,
295 nativeEvent: AnyNativeEvent,
296 ): QueuedReplayableEvent {
297 return {
@@ -299,7 +299,7 @@ function createQueuedReplayableEvent(
299 topLevelType,
300 eventSystemFlags: eventSystemFlags | IS_REPLAYED,
301 nativeEvent,
302 - targetContainers: targetContainer !== null ? [targetContainer] : [],
302 + targetContainers: [targetContainer],
303 };
304 }
305
@@ -307,7 +307,7 @@ export function queueDiscreteEvent(
307 blockedOn: null | Container | SuspenseInstance,
308 topLevelType: DOMTopLevelEventType,
309 eventSystemFlags: EventSystemFlags,
310 - targetContainer: EventTarget | null,
310 + targetContainer: EventTarget,
311 nativeEvent: AnyNativeEvent,
312 ): void {
313 const queuedEvent = createQueuedReplayableEvent(
@@ -382,7 +382,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
382 blockedOn: null | Container | SuspenseInstance,
383 topLevelType: DOMTopLevelEventType,
384 eventSystemFlags: EventSystemFlags,
385 - targetContainer: EventTarget | null,
385 + targetContainer: EventTarget,
386 nativeEvent: AnyNativeEvent,
387 ): QueuedReplayableEvent {
388 if (
@@ -424,7 +424,7 @@ export function queueIfContinuousEvent(
424 blockedOn: null | Container | SuspenseInstance,
425 topLevelType: DOMTopLevelEventType,
426 eventSystemFlags: EventSystemFlags,
427 - targetContainer: EventTarget | null,
427 + targetContainer: EventTarget,
428 nativeEvent: AnyNativeEvent,
429 ): boolean {
430 // These set relatedTarget to null because the replayed event will be treated as if we
packages/react-dom/src/test-utils/ReactTestUtils.js
+160 -151
@@ -22,6 +22,7 @@ import * as DOMTopLevelEventTypes from '../events/DOMTopLevelEventTypes';
22 import act from './ReactTestUtilsAct';
23 import forEachAccumulated from 'legacy-events/forEachAccumulated';
24 import accumulateInto from 'legacy-events/accumulateInto';
25 +import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
26
27 const {findDOMNode} = ReactDOM;
28 // Keep in sync with ReactDOMUnstableNativeDependencies.js
@@ -53,34 +54,6 @@ let didWarnSimulateNativeDeprecated = false;
54 * @class ReactTestUtils
55 */
56
56 -/**
57 - * Simulates a top level event being dispatched from a raw event that occurred
58 - * on an `Element` node.
59 - * @param {number} topLevelType A number from `TopLevelEventTypes`
60 - * @param {!Element} node The dom to simulate an event occurring on.
61 - * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
62 - */
63 -function simulateNativeEventOnNode(topLevelType, node, fakeNativeEvent) {
64 - fakeNativeEvent.target = node;
65 - const PLUGIN_EVENT_SYSTEM = 1;
66 - dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, null, fakeNativeEvent);
67 -}
68 -
69 -/**
70 - * Simulates a top level event being dispatched from a raw event that occurred
71 - * on the `ReactDOMComponent` `comp`.
72 - * @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`.
73 - * @param {!ReactDOMComponent} comp
74 - * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
75 - */
76 -function simulateNativeEventOnDOMComponent(
77 - topLevelType,
78 - comp,
79 - fakeNativeEvent,
80 -) {
81 - simulateNativeEventOnNode(topLevelType, findDOMNode(comp), fakeNativeEvent);
82 -}
83 -
57 function findAllInRenderedFiberTreeInternal(fiber, test) {
58 if (!fiber) {
59 return [];
@@ -531,7 +504,7 @@ function accumulateTwoPhaseDispatches(events) {
504 // End of inline
505
506 const Simulate = {};
534 -const SimulateNative = {};
507 +let SimulateNative;
508
509 /**
510 * Exports:
@@ -605,134 +578,170 @@ function buildSimulators() {
578
579 buildSimulators();
580
608 -/**
609 - * Exports:
610 - *
611 - * - `SimulateNative.click(Element/ReactDOMComponent)`
612 - * - `SimulateNative.mouseMove(Element/ReactDOMComponent)`
613 - * - `SimulateNative.mouseIn/ReactDOMComponent)`
614 - * - `SimulateNative.mouseOut(Element/ReactDOMComponent)`
615 - * - ... (All keys from `BrowserEventConstants.topLevelTypes`)
616 - *
617 - * Note: Top level event types are a subset of the entire set of handler types
618 - * (which include a broader set of "synthetic" events). For example, onDragDone
619 - * is a synthetic event. Except when testing an event plugin or React's event
620 - * handling code specifically, you probably want to use Simulate
621 - * to dispatch synthetic events.
622 - */
581 +if (!enableModernEventSystem) {
582 + SimulateNative = {};
583
624 -function makeNativeSimulator(eventType, topLevelType) {
625 - return function(domComponentOrNode, nativeEventData) {
626 - if (__DEV__) {
627 - if (!didWarnSimulateNativeDeprecated) {
628 - didWarnSimulateNativeDeprecated = true;
629 - console.warn(
630 - 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
631 - 'how the browser dispatches events, and will be removed in a future major ' +
632 - 'version of React. If you rely on it for testing, consider attaching the root ' +
633 - 'DOM container to the document during the test, and then dispatching native browser ' +
634 - 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
635 - 'the `bubbles` flag to `true` when creating the native browser event.',
636 - );
637 - }
638 - }
584 + /**
585 + * Simulates a top level event being dispatched from a raw event that occurred
586 + * on an `Element` node.
587 + * @param {number} topLevelType A number from `TopLevelEventTypes`
588 + * @param {!Element} node The dom to simulate an event occurring on.
589 + * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
590 + */
591 + const simulateNativeEventOnNode = function(
592 + topLevelType,
593 + node,
594 + fakeNativeEvent,
595 + ) {
596 + fakeNativeEvent.target = node;
597 + const PLUGIN_EVENT_SYSTEM = 1;
598 + dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, null, fakeNativeEvent);
599 + };
600
640 - const fakeNativeEvent = new Event(eventType);
641 - Object.assign(fakeNativeEvent, nativeEventData);
642 - if (isDOMComponent(domComponentOrNode)) {
643 - simulateNativeEventOnDOMComponent(
644 - topLevelType,
645 - domComponentOrNode,
646 - fakeNativeEvent,
647 - );
648 - } else if (domComponentOrNode.tagName) {
649 - // Will allow on actual dom nodes.
650 - simulateNativeEventOnNode(
651 - topLevelType,
652 - domComponentOrNode,
653 - fakeNativeEvent,
654 - );
655 - }
601 + /**
602 + * Simulates a top level event being dispatched from a raw event that occurred
603 + * on the `ReactDOMComponent` `comp`.
604 + * @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`.
605 + * @param {!ReactDOMComponent} comp
606 + * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
607 + */
608 + const simulateNativeEventOnDOMComponent = function(
609 + topLevelType,
610 + comp,
611 + fakeNativeEvent,
612 + ) {
613 + simulateNativeEventOnNode(topLevelType, findDOMNode(comp), fakeNativeEvent);
614 };
657 -}
615
659 -[
660 - [DOMTopLevelEventTypes.TOP_ABORT, 'abort'],
661 - [DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd'],
662 - [DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration'],
663 - [DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart'],
664 - [DOMTopLevelEventTypes.TOP_BLUR, 'blur'],
665 - [DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough'],
666 - [DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay'],
667 - [DOMTopLevelEventTypes.TOP_CANCEL, 'cancel'],
668 - [DOMTopLevelEventTypes.TOP_CHANGE, 'change'],
669 - [DOMTopLevelEventTypes.TOP_CLICK, 'click'],
670 - [DOMTopLevelEventTypes.TOP_CLOSE, 'close'],
671 - [DOMTopLevelEventTypes.TOP_COMPOSITION_END, 'compositionEnd'],
672 - [DOMTopLevelEventTypes.TOP_COMPOSITION_START, 'compositionStart'],
673 - [DOMTopLevelEventTypes.TOP_COMPOSITION_UPDATE, 'compositionUpdate'],
674 - [DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu'],
675 - [DOMTopLevelEventTypes.TOP_COPY, 'copy'],
676 - [DOMTopLevelEventTypes.TOP_CUT, 'cut'],
677 - [DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick'],
678 - [DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd'],
679 - [DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter'],
680 - [DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit'],
681 - [DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave'],
682 - [DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver'],
683 - [DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart'],
684 - [DOMTopLevelEventTypes.TOP_DRAG, 'drag'],
685 - [DOMTopLevelEventTypes.TOP_DROP, 'drop'],
686 - [DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange'],
687 - [DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied'],
688 - [DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted'],
689 - [DOMTopLevelEventTypes.TOP_ENDED, 'ended'],
690 - [DOMTopLevelEventTypes.TOP_ERROR, 'error'],
691 - [DOMTopLevelEventTypes.TOP_FOCUS, 'focus'],
692 - [DOMTopLevelEventTypes.TOP_INPUT, 'input'],
693 - [DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown'],
694 - [DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress'],
695 - [DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp'],
696 - [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
697 - [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
698 - [DOMTopLevelEventTypes.TOP_LOAD, 'load'],
699 - [DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData'],
700 - [DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata'],
701 - [DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown'],
702 - [DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove'],
703 - [DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut'],
704 - [DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver'],
705 - [DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp'],
706 - [DOMTopLevelEventTypes.TOP_PASTE, 'paste'],
707 - [DOMTopLevelEventTypes.TOP_PAUSE, 'pause'],
708 - [DOMTopLevelEventTypes.TOP_PLAY, 'play'],
709 - [DOMTopLevelEventTypes.TOP_PLAYING, 'playing'],
710 - [DOMTopLevelEventTypes.TOP_PROGRESS, 'progress'],
711 - [DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange'],
712 - [DOMTopLevelEventTypes.TOP_SCROLL, 'scroll'],
713 - [DOMTopLevelEventTypes.TOP_SEEKED, 'seeked'],
714 - [DOMTopLevelEventTypes.TOP_SEEKING, 'seeking'],
715 - [DOMTopLevelEventTypes.TOP_SELECTION_CHANGE, 'selectionChange'],
716 - [DOMTopLevelEventTypes.TOP_STALLED, 'stalled'],
717 - [DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend'],
718 - [DOMTopLevelEventTypes.TOP_TEXT_INPUT, 'textInput'],
719 - [DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate'],
720 - [DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle'],
721 - [DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel'],
722 - [DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd'],
723 - [DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove'],
724 - [DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart'],
725 - [DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd'],
726 - [DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange'],
727 - [DOMTopLevelEventTypes.TOP_WAITING, 'waiting'],
728 - [DOMTopLevelEventTypes.TOP_WHEEL, 'wheel'],
729 -].forEach(([topLevelType, eventType]) => {
616 /**
731 - * @param {!Element|ReactDOMComponent} domComponentOrNode
732 - * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
617 + * Exports:
618 + *
619 + * - `SimulateNative.click(Element/ReactDOMComponent)`
620 + * - `SimulateNative.mouseMove(Element/ReactDOMComponent)`
621 + * - `SimulateNative.mouseIn/ReactDOMComponent)`
622 + * - `SimulateNative.mouseOut(Element/ReactDOMComponent)`
623 + * - ... (All keys from `BrowserEventConstants.topLevelTypes`)
624 + *
625 + * Note: Top level event types are a subset of the entire set of handler types
626 + * (which include a broader set of "synthetic" events). For example, onDragDone
627 + * is a synthetic event. Except when testing an event plugin or React's event
628 + * handling code specifically, you probably want to use Simulate
629 + * to dispatch synthetic events.
630 */
734 - SimulateNative[eventType] = makeNativeSimulator(eventType, topLevelType);
735 -});
631 +
632 + const makeNativeSimulator = function(eventType, topLevelType) {
633 + return function(domComponentOrNode, nativeEventData) {
634 + if (__DEV__) {
635 + if (!didWarnSimulateNativeDeprecated) {
636 + didWarnSimulateNativeDeprecated = true;
637 + console.warn(
638 + 'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
639 + 'how the browser dispatches events, and will be removed in a future major ' +
640 + 'version of React. If you rely on it for testing, consider attaching the root ' +
641 + 'DOM container to the document during the test, and then dispatching native browser ' +
642 + 'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
643 + 'the `bubbles` flag to `true` when creating the native browser event.',
644 + );
645 + }
646 + }
647 +
648 + const fakeNativeEvent = new Event(eventType);
649 + Object.assign(fakeNativeEvent, nativeEventData);
650 + if (isDOMComponent(domComponentOrNode)) {
651 + simulateNativeEventOnDOMComponent(
652 + topLevelType,
653 + domComponentOrNode,
654 + fakeNativeEvent,
655 + );
656 + } else if (domComponentOrNode.tagName) {
657 + // Will allow on actual dom nodes.
658 + simulateNativeEventOnNode(
659 + topLevelType,
660 + domComponentOrNode,
661 + fakeNativeEvent,
662 + );
663 + }
664 + };
665 + };
666 +
667 + [
668 + [DOMTopLevelEventTypes.TOP_ABORT, 'abort'],
669 + [DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd'],
670 + [DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration'],
671 + [DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart'],
672 + [DOMTopLevelEventTypes.TOP_BLUR, 'blur'],
673 + [DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough'],
674 + [DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay'],
675 + [DOMTopLevelEventTypes.TOP_CANCEL, 'cancel'],
676 + [DOMTopLevelEventTypes.TOP_CHANGE, 'change'],
677 + [DOMTopLevelEventTypes.TOP_CLICK, 'click'],
678 + [DOMTopLevelEventTypes.TOP_CLOSE, 'close'],
679 + [DOMTopLevelEventTypes.TOP_COMPOSITION_END, 'compositionEnd'],
680 + [DOMTopLevelEventTypes.TOP_COMPOSITION_START, 'compositionStart'],
681 + [DOMTopLevelEventTypes.TOP_COMPOSITION_UPDATE, 'compositionUpdate'],
682 + [DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu'],
683 + [DOMTopLevelEventTypes.TOP_COPY, 'copy'],
684 + [DOMTopLevelEventTypes.TOP_CUT, 'cut'],
685 + [DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick'],
686 + [DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd'],
687 + [DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter'],
688 + [DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit'],
689 + [DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave'],
690 + [DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver'],
691 + [DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart'],
692 + [DOMTopLevelEventTypes.TOP_DRAG, 'drag'],
693 + [DOMTopLevelEventTypes.TOP_DROP, 'drop'],
694 + [DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange'],
695 + [DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied'],
696 + [DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted'],
697 + [DOMTopLevelEventTypes.TOP_ENDED, 'ended'],
698 + [DOMTopLevelEventTypes.TOP_ERROR, 'error'],
699 + [DOMTopLevelEventTypes.TOP_FOCUS, 'focus'],
700 + [DOMTopLevelEventTypes.TOP_INPUT, 'input'],
701 + [DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown'],
702 + [DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress'],
703 + [DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp'],
704 + [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
705 + [DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
706 + [DOMTopLevelEventTypes.TOP_LOAD, 'load'],
707 + [DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData'],
708 + [DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata'],
709 + [DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown'],
710 + [DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove'],
711 + [DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut'],
712 + [DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver'],
713 + [DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp'],
714 + [DOMTopLevelEventTypes.TOP_PASTE, 'paste'],
715 + [DOMTopLevelEventTypes.TOP_PAUSE, 'pause'],
716 + [DOMTopLevelEventTypes.TOP_PLAY, 'play'],
717 + [DOMTopLevelEventTypes.TOP_PLAYING, 'playing'],
718 + [DOMTopLevelEventTypes.TOP_PROGRESS, 'progress'],
719 + [DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange'],
720 + [DOMTopLevelEventTypes.TOP_SCROLL, 'scroll'],
721 + [DOMTopLevelEventTypes.TOP_SEEKED, 'seeked'],
722 + [DOMTopLevelEventTypes.TOP_SEEKING, 'seeking'],
723 + [DOMTopLevelEventTypes.TOP_SELECTION_CHANGE, 'selectionChange'],
724 + [DOMTopLevelEventTypes.TOP_STALLED, 'stalled'],
725 + [DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend'],
726 + [DOMTopLevelEventTypes.TOP_TEXT_INPUT, 'textInput'],
727 + [DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate'],
728 + [DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle'],
729 + [DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel'],
730 + [DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd'],
731 + [DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove'],
732 + [DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart'],
733 + [DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd'],
734 + [DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange'],
735 + [DOMTopLevelEventTypes.TOP_WAITING, 'waiting'],
736 + [DOMTopLevelEventTypes.TOP_WHEEL, 'wheel'],
737 + ].forEach(([topLevelType, eventType]) => {
738 + /**
739 + * @param {!Element|ReactDOMComponent} domComponentOrNode
740 + * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
741 + */
742 + SimulateNative[eventType] = makeNativeSimulator(eventType, topLevelType);
743 + });
744 +}
745
746 export {
747 renderIntoDocument,