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,