mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Don't use magic browser event dispatching for simulated events
When calling ReactTestUtils.Simulate, sometimes you want to test that an exception is thrown by the event handler. This lets you do that without relying on the fact that old jsdom doesn't implement `Event`.
This commit is contained in:
@@ -96,7 +96,7 @@ function manualDispatchChangeEvent(nativeEvent) {
|
||||
|
||||
function runEventInBatch(event) {
|
||||
EventPluginHub.enqueueEvents(event);
|
||||
EventPluginHub.processEventQueue();
|
||||
EventPluginHub.processEventQueue(false);
|
||||
}
|
||||
|
||||
function startWatchingForChangeEventIE8(target, targetID) {
|
||||
|
||||
@@ -35,17 +35,24 @@ var eventQueue = null;
|
||||
* Dispatches an event and releases it back into the pool, unless persistent.
|
||||
*
|
||||
* @param {?object} event Synthetic event to be dispatched.
|
||||
* @param {boolean} simulated If the event is simulated (changes exn behavior)
|
||||
* @private
|
||||
*/
|
||||
var executeDispatchesAndRelease = function(event) {
|
||||
var executeDispatchesAndRelease = function(event, simulated) {
|
||||
if (event) {
|
||||
EventPluginUtils.executeDispatchesInOrder(event);
|
||||
EventPluginUtils.executeDispatchesInOrder(event, simulated);
|
||||
|
||||
if (!event.isPersistent()) {
|
||||
event.constructor.release(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
var executeDispatchesAndReleaseSimulated = function(e) {
|
||||
return executeDispatchesAndRelease(e, true);
|
||||
};
|
||||
var executeDispatchesAndReleaseTopLevel = function(e) {
|
||||
return executeDispatchesAndRelease(e, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* - `InstanceHandle`: [required] Module that performs logical traversals of DOM
|
||||
@@ -266,12 +273,22 @@ var EventPluginHub = {
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
processEventQueue: function() {
|
||||
processEventQueue: function(simulated) {
|
||||
// Set `eventQueue` to null before processing it so that we can tell if more
|
||||
// events get enqueued while processing.
|
||||
var processingEventQueue = eventQueue;
|
||||
eventQueue = null;
|
||||
forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
|
||||
if (simulated) {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseSimulated
|
||||
);
|
||||
} else {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseTopLevel
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!eventQueue,
|
||||
'processEventQueue(): Additional events were enqueued while processing ' +
|
||||
|
||||
@@ -80,20 +80,30 @@ if (__DEV__) {
|
||||
/**
|
||||
* Dispatch the event to the listener.
|
||||
* @param {SyntheticEvent} event SyntheticEvent to handle
|
||||
* @param {boolean} simulated If the event is simulated (changes exn behavior)
|
||||
* @param {function} listener Application-level callback
|
||||
* @param {string} domID DOM id to pass to the callback.
|
||||
*/
|
||||
function executeDispatch(event, listener, domID) {
|
||||
function executeDispatch(event, simulated, listener, domID) {
|
||||
var type = event.type || 'unknown-event';
|
||||
event.currentTarget = injection.Mount.getNode(domID);
|
||||
ReactErrorUtils.invokeGuardedCallback(type, listener, event, domID);
|
||||
if (simulated) {
|
||||
ReactErrorUtils.invokeGuardedCallbackWithCatch(
|
||||
type,
|
||||
listener,
|
||||
event,
|
||||
domID
|
||||
);
|
||||
} else {
|
||||
ReactErrorUtils.invokeGuardedCallback(type, listener, event, domID);
|
||||
}
|
||||
event.currentTarget = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard/simple iteration through an event's collected dispatches.
|
||||
*/
|
||||
function executeDispatchesInOrder(event) {
|
||||
function executeDispatchesInOrder(event, simulated) {
|
||||
var dispatchListeners = event._dispatchListeners;
|
||||
var dispatchIDs = event._dispatchIDs;
|
||||
if (__DEV__) {
|
||||
@@ -105,10 +115,10 @@ function executeDispatchesInOrder(event) {
|
||||
break;
|
||||
}
|
||||
// Listeners and IDs are two parallel arrays that are always in sync.
|
||||
executeDispatch(event, dispatchListeners[i], dispatchIDs[i]);
|
||||
executeDispatch(event, simulated, dispatchListeners[i], dispatchIDs[i]);
|
||||
}
|
||||
} else if (dispatchListeners) {
|
||||
executeDispatch(event, dispatchListeners, dispatchIDs);
|
||||
executeDispatch(event, simulated, dispatchListeners, dispatchIDs);
|
||||
}
|
||||
event._dispatchListeners = null;
|
||||
event._dispatchIDs = null;
|
||||
|
||||
@@ -306,7 +306,7 @@ var run = function(config, hierarchyConfig, nativeEventConfig) {
|
||||
// extraction process, but not the side effectful events. Below, we dispatch
|
||||
// side effectful events.
|
||||
EventPluginHub.enqueueEvents(extractedEvents);
|
||||
EventPluginHub.processEventQueue();
|
||||
EventPluginHub.processEventQueue(true);
|
||||
|
||||
// Ensure that every event that declared an `order`, was actually dispatched.
|
||||
expect(
|
||||
|
||||
@@ -15,7 +15,7 @@ var EventPluginHub = require('EventPluginHub');
|
||||
|
||||
function runEventQueueInBatch(events) {
|
||||
EventPluginHub.enqueueEvents(events);
|
||||
EventPluginHub.processEventQueue();
|
||||
EventPluginHub.processEventQueue(false);
|
||||
}
|
||||
|
||||
var ReactEventEmitterMixin = {
|
||||
|
||||
@@ -14,25 +14,33 @@
|
||||
|
||||
var caughtError = null;
|
||||
|
||||
var ReactErrorUtils = {
|
||||
/**
|
||||
* Call a function while guarding against errors that happens within it.
|
||||
*
|
||||
* @param {?String} name of the guard to use for logging or debugging
|
||||
* @param {Function} func The function to invoke
|
||||
* @param {*} a First argument
|
||||
* @param {*} b Second argument
|
||||
*/
|
||||
invokeGuardedCallback: function(name, func, a, b) {
|
||||
try {
|
||||
return func(a, b);
|
||||
} catch (x) {
|
||||
if (caughtError === null) {
|
||||
caughtError = x;
|
||||
}
|
||||
return undefined;
|
||||
/**
|
||||
* Call a function while guarding against errors that happens within it.
|
||||
*
|
||||
* @param {?String} name of the guard to use for logging or debugging
|
||||
* @param {Function} func The function to invoke
|
||||
* @param {*} a First argument
|
||||
* @param {*} b Second argument
|
||||
*/
|
||||
function invokeGuardedCallback(name, func, a, b) {
|
||||
try {
|
||||
return func(a, b);
|
||||
} catch (x) {
|
||||
if (caughtError === null) {
|
||||
caughtError = x;
|
||||
}
|
||||
},
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
var ReactErrorUtils = {
|
||||
invokeGuardedCallback: invokeGuardedCallback,
|
||||
|
||||
/**
|
||||
* Invoked by ReactTestUtils.Simulate so that any errors thrown by the event
|
||||
* handler are sure to be rethrown by rethrowCaughtError.
|
||||
*/
|
||||
invokeGuardedCallbackWithCatch: invokeGuardedCallback,
|
||||
|
||||
/**
|
||||
* During execution of guarded functions we will capture the first error which
|
||||
|
||||
@@ -475,7 +475,7 @@ function makeSimulator(eventType) {
|
||||
|
||||
ReactUpdates.batchedUpdates(function() {
|
||||
EventPluginHub.enqueueEvents(event);
|
||||
EventPluginHub.processEventQueue();
|
||||
EventPluginHub.processEventQueue(true);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user