mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Simulate synthetic events using ReactTestUtils
Most of the time this is what you want to do, so I've renamed what was Simulate to be SimulateNative. Now Simulate.change does what you expect, so this fixes #517 and fixes #519.
This commit is contained in:
@@ -318,6 +318,8 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
|
||||
}
|
||||
},
|
||||
|
||||
eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
|
||||
|
||||
registrationNameModules: EventPluginHub.registrationNameModules,
|
||||
|
||||
putListener: EventPluginHub.putListener,
|
||||
|
||||
@@ -142,10 +142,10 @@ describe('ReactEventEmitter', function() {
|
||||
it('should not invoke handlers if ReactEventEmitter is disabled', function() {
|
||||
registerSimpleTestHandler();
|
||||
ReactEventEmitter.setEnabled(false);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(0);
|
||||
ReactEventEmitter.setEnabled(true);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -312,11 +312,11 @@ describe('ReactEventEmitter', function() {
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getID(CHILD))
|
||||
);
|
||||
ReactTestUtils.Simulate.touchStart(
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
ReactTestUtils.Simulate.touchEnd(
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
@@ -330,11 +330,11 @@ describe('ReactEventEmitter', function() {
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getID(CHILD))
|
||||
);
|
||||
ReactTestUtils.Simulate.touchStart(
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
ReactTestUtils.Simulate.touchEnd(
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1)
|
||||
);
|
||||
@@ -348,11 +348,11 @@ describe('ReactEventEmitter', function() {
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getID(CHILD))
|
||||
);
|
||||
ReactTestUtils.Simulate.touchStart(
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
ReactTestUtils.Simulate.touchEnd(
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold + 1)
|
||||
);
|
||||
@@ -415,11 +415,11 @@ describe('ReactEventEmitter', function() {
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getID(GRANDPARENT))
|
||||
);
|
||||
ReactTestUtils.Simulate.touchStart(
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
ReactTestUtils.Simulate.touchEnd(
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
|
||||
@@ -125,7 +125,7 @@ describe('ReactDOMInput', function() {
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
node.value = 'giraffe';
|
||||
ReactTestUtils.Simulate.input(node);
|
||||
ReactTestUtils.Simulate.change(node);
|
||||
expect(node.value).toBe('0');
|
||||
});
|
||||
|
||||
@@ -171,9 +171,8 @@ describe('ReactDOMInput', function() {
|
||||
aNode.checked = false;
|
||||
expect(cNode.checked).toBe(true);
|
||||
|
||||
// Now let's run the actual ReactDOMInput change event handler (on radio
|
||||
// inputs, ChangeEventPlugin listens for the `click` event so trigger that)
|
||||
ReactTestUtils.Simulate.click(bNode);
|
||||
// Now let's run the actual ReactDOMInput change event handler
|
||||
ReactTestUtils.Simulate.change(bNode);
|
||||
|
||||
// The original state should have been restored
|
||||
expect(aNode.checked).toBe(true);
|
||||
@@ -192,7 +191,7 @@ describe('ReactDOMInput', function() {
|
||||
expect(link.requestChange.mock.calls.length).toBe(0);
|
||||
|
||||
instance.getDOMNode().value = 'test';
|
||||
ReactTestUtils.Simulate.input(instance.getDOMNode());
|
||||
ReactTestUtils.Simulate.change(instance.getDOMNode());
|
||||
|
||||
expect(link.requestChange.mock.calls.length).toBe(1);
|
||||
expect(link.requestChange.mock.calls[0][0]).toEqual('test');
|
||||
@@ -265,7 +264,7 @@ describe('ReactDOMInput', function() {
|
||||
expect(link.requestChange.mock.calls.length).toBe(0);
|
||||
|
||||
instance.getDOMNode().checked = false;
|
||||
ReactTestUtils.Simulate.click(instance.getDOMNode());
|
||||
ReactTestUtils.Simulate.change(instance.getDOMNode());
|
||||
|
||||
expect(link.requestChange.mock.calls.length).toBe(1);
|
||||
expect(link.requestChange.mock.calls[0][0]).toEqual(false);
|
||||
|
||||
@@ -139,7 +139,7 @@ describe('ReactDOMTextarea', function() {
|
||||
var node = renderTextarea(stub);
|
||||
|
||||
node.value = 'giraffe';
|
||||
ReactTestUtils.Simulate.input(node);
|
||||
ReactTestUtils.Simulate.change(node);
|
||||
expect(node.value).toBe('0');
|
||||
});
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('ReactDOMTextarea', function() {
|
||||
expect(link.requestChange.mock.calls.length).toBe(0);
|
||||
|
||||
instance.getDOMNode().value = 'test';
|
||||
ReactTestUtils.Simulate.input(instance.getDOMNode());
|
||||
ReactTestUtils.Simulate.change(instance.getDOMNode());
|
||||
|
||||
expect(link.requestChange.mock.calls.length).toBe(1);
|
||||
expect(link.requestChange.mock.calls[0][0]).toEqual('test');
|
||||
|
||||
@@ -99,14 +99,14 @@ describe('AnalyticsEventPlugin', function() {
|
||||
|
||||
// Simulate some clicks
|
||||
for (var i = 0; i < numClickEvents; i++) {
|
||||
ReactTestUtils.Simulate.click(renderedComponent.refs.testDiv);
|
||||
ReactTestUtils.SimulateNative.click(renderedComponent.refs.testDiv);
|
||||
}
|
||||
// Simulate some double clicks
|
||||
for (i = 0; i < numDoubleClickEvents; i++) {
|
||||
ReactTestUtils.Simulate.doubleClick(renderedComponent.refs.testDiv);
|
||||
ReactTestUtils.SimulateNative.doubleClick(renderedComponent.refs.testDiv);
|
||||
}
|
||||
// Simulate some other events not being tracked for analytics
|
||||
ReactTestUtils.Simulate.focus(renderedComponent.refs.testDiv);
|
||||
ReactTestUtils.SimulateNative.focus(renderedComponent.refs.testDiv);
|
||||
|
||||
window.mockRunTimersOnce();
|
||||
expect(cb).toBeCalled();
|
||||
@@ -143,7 +143,7 @@ describe('AnalyticsEventPlugin', function() {
|
||||
|
||||
var error = false;
|
||||
try {
|
||||
ReactTestUtils.Simulate.click(renderedComponent.refs.testDiv);
|
||||
ReactTestUtils.SimulateNative.click(renderedComponent.refs.testDiv);
|
||||
} catch(e) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ describe('autobinding', function() {
|
||||
render: function() {
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={this.onMouseEnter.bind(this)}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
onMouseOver={this.onMouseEnter.bind(this)}
|
||||
onMouseOut={this.onMouseLeave}
|
||||
onClick={this.onClick}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -141,6 +141,8 @@ var EventPluginHub = {
|
||||
|
||||
},
|
||||
|
||||
eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
|
||||
|
||||
registrationNameModules: EventPluginRegistry.registrationNameModules,
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,6 +85,14 @@ function recomputePluginOrdering() {
|
||||
* @private
|
||||
*/
|
||||
function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
|
||||
invariant(
|
||||
!EventPluginRegistry.eventNameDispatchConfigs[eventName],
|
||||
'EventPluginHub: More than one plugin attempted to publish the same ' +
|
||||
'event name, `%s`.',
|
||||
eventName
|
||||
);
|
||||
EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
|
||||
|
||||
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
|
||||
if (phasedRegistrationNames) {
|
||||
for (var phaseName in phasedRegistrationNames) {
|
||||
@@ -142,7 +150,12 @@ var EventPluginRegistry = {
|
||||
plugins: [],
|
||||
|
||||
/**
|
||||
* Mapping from registration names to plugin modules.
|
||||
* Mapping from event name to dispatch config
|
||||
*/
|
||||
eventNameDispatchConfigs: {},
|
||||
|
||||
/**
|
||||
* Mapping from registration name to plugin module
|
||||
*/
|
||||
registrationNameModules: {},
|
||||
|
||||
@@ -243,6 +256,14 @@ var EventPluginRegistry = {
|
||||
}
|
||||
}
|
||||
EventPluginRegistry.plugins.length = 0;
|
||||
|
||||
var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
|
||||
for (var eventName in eventNameDispatchConfigs) {
|
||||
if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
|
||||
delete eventNameDispatchConfigs[eventName];
|
||||
}
|
||||
}
|
||||
|
||||
var registrationNameModules = EventPluginRegistry.registrationNameModules;
|
||||
for (var registrationName in registrationNameModules) {
|
||||
if (registrationNameModules.hasOwnProperty(registrationName)) {
|
||||
|
||||
+71
-18
@@ -16,12 +16,19 @@
|
||||
* @providesModule ReactTestUtils
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var React = require('React');
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactDOM = require('ReactDOM');
|
||||
var ReactEventEmitter = require('ReactEventEmitter');
|
||||
var ReactMount = require('ReactMount');
|
||||
var ReactTextComponent = require('ReactTextComponent');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
var mergeInto = require('mergeInto');
|
||||
var copyProperties = require('copyProperties');
|
||||
@@ -227,12 +234,12 @@ var ReactTestUtils = {
|
||||
|
||||
/**
|
||||
* Simulates a top level event being dispatched from a raw event that occured
|
||||
* on and `Element` node.
|
||||
* on an `Element` node.
|
||||
* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`
|
||||
* @param {!Element} node The dom to simulate an event occurring on.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateEventOnNode: function(topLevelType, node, fakeNativeEvent) {
|
||||
simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
|
||||
var virtualHandler =
|
||||
ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback(
|
||||
topLevelType
|
||||
@@ -248,8 +255,11 @@ var ReactTestUtils = {
|
||||
* @param comp {!ReactDOMComponent}
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateEventOnDOMComponent: function(topLevelType, comp, fakeNativeEvent) {
|
||||
ReactTestUtils.simulateEventOnNode(
|
||||
simulateNativeEventOnDOMComponent: function(
|
||||
topLevelType,
|
||||
comp,
|
||||
fakeNativeEvent) {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
topLevelType,
|
||||
comp.getDOMNode(),
|
||||
fakeNativeEvent
|
||||
@@ -264,7 +274,8 @@ var ReactTestUtils = {
|
||||
};
|
||||
},
|
||||
|
||||
Simulate: null // Will populate
|
||||
Simulate: {},
|
||||
SimulateNative: {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -272,33 +283,75 @@ var ReactTestUtils = {
|
||||
*
|
||||
* - `ReactTestUtils.Simulate.click(Element/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.Simulate.mouseMove(Element/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.Simulate.mouseIn/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.Simulate.mouseOut(Element/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.Simulate.change(Element/ReactDOMComponent)`
|
||||
* - ... (All keys from event plugin `eventTypes` objects)
|
||||
*/
|
||||
function makeSimulator(eventType) {
|
||||
return function(domComponentOrNode, eventData) {
|
||||
var node;
|
||||
if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
|
||||
node = domComponentOrNode.getDOMNode();
|
||||
} else if (domComponentOrNode.tagName) {
|
||||
node = domComponentOrNode;
|
||||
}
|
||||
|
||||
var fakeNativeEvent = new Event();
|
||||
fakeNativeEvent.target = node;
|
||||
// We don't use SyntheticEvent.getPooled in order to not have to worry about
|
||||
// properly destroying any properties assigned from `eventData` upon release
|
||||
var event = new SyntheticEvent(
|
||||
ReactEventEmitter.eventNameDispatchConfigs[eventType],
|
||||
ReactMount.getID(node),
|
||||
fakeNativeEvent
|
||||
);
|
||||
mergeInto(event, eventData);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
|
||||
ReactUpdates.batchedUpdates(function() {
|
||||
EventPluginHub.enqueueEvents(event);
|
||||
EventPluginHub.processEventQueue();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var eventType;
|
||||
for (eventType in ReactEventEmitter.eventNameDispatchConfigs) {
|
||||
/**
|
||||
* @param {!Element || ReactDOMComponent} domComponentOrNode
|
||||
* @param {?object} eventData Fake event data to use in SyntheticEvent.
|
||||
*/
|
||||
ReactTestUtils.Simulate[eventType] = makeSimulator(eventType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports:
|
||||
*
|
||||
* - `ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent)`
|
||||
* - `ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent)`
|
||||
* - ... (All keys from `EventConstants.topLevelTypes`)
|
||||
*
|
||||
* Note: Top level event types are a subset of the entire set of handler types
|
||||
* (which include a broader set of "synthetic" events). For example, onDragDone
|
||||
* is a synthetic event. You certainly may write test cases for these event
|
||||
* types, but it doesn't make sense to simulate them at this low of a level. In
|
||||
* this case, the way you test an `onDragDone` event is by simulating a series
|
||||
* of `mouseMove`/ `mouseDown`/`mouseUp` events - Then, a synthetic event of
|
||||
* type `onDragDone` will be constructed and dispached through your system
|
||||
* automatically.
|
||||
* is a synthetic event. Except when testing an event plugin or React's event
|
||||
* handling code specifically, you probably want to use ReactTestUtils.Simulate
|
||||
* to dispatch synthetic events.
|
||||
*/
|
||||
|
||||
function makeSimulator(eventType) {
|
||||
function makeNativeSimulator(eventType) {
|
||||
return function(domComponentOrNode, nativeEventData) {
|
||||
var fakeNativeEvent = new Event(eventType);
|
||||
mergeInto(fakeNativeEvent, nativeEventData);
|
||||
if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
|
||||
ReactTestUtils.simulateEventOnDOMComponent(
|
||||
ReactTestUtils.simulateNativeEventOnDOMComponent(
|
||||
eventType,
|
||||
domComponentOrNode,
|
||||
fakeNativeEvent
|
||||
);
|
||||
} else if (!!domComponentOrNode.tagName) {
|
||||
// Will allow on actual dom nodes.
|
||||
ReactTestUtils.simulateEventOnNode(
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
eventType,
|
||||
domComponentOrNode,
|
||||
fakeNativeEvent
|
||||
@@ -307,7 +360,6 @@ function makeSimulator(eventType) {
|
||||
};
|
||||
}
|
||||
|
||||
ReactTestUtils.Simulate = {};
|
||||
var eventType;
|
||||
for (eventType in topLevelTypes) {
|
||||
// Event type is stored as 'topClick' - we transform that to 'click'
|
||||
@@ -317,7 +369,8 @@ for (eventType in topLevelTypes) {
|
||||
* @param {!Element || ReactDOMComponent} domComponentOrNode
|
||||
* @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
ReactTestUtils.Simulate[convenienceName] = makeSimulator(eventType);
|
||||
ReactTestUtils.SimulateNative[convenienceName] =
|
||||
makeNativeSimulator(eventType);
|
||||
}
|
||||
|
||||
module.exports = ReactTestUtils;
|
||||
|
||||
Reference in New Issue
Block a user