react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / test / ReactTestUtils.js
81152 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule ReactTestUtils9*/1011"use strict";1213var EventConstants = require('EventConstants');14var EventPluginHub = require('EventPluginHub');15var EventPropagators = require('EventPropagators');16var React = require('React');17var ReactElement = require('ReactElement');18var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');19var ReactMount = require('ReactMount');20var ReactTextComponent = require('ReactTextComponent');21var ReactUpdates = require('ReactUpdates');22var SyntheticEvent = require('SyntheticEvent');2324var assign = require('Object.assign');2526var topLevelTypes = EventConstants.topLevelTypes;2728function Event(suffix) {}2930/**31* @class ReactTestUtils32*/3334/**35* Todo: Support the entire DOM.scry query syntax. For now, these simple36* utilities will suffice for testing purposes.37* @lends ReactTestUtils38*/39var ReactTestUtils = {40renderIntoDocument: function(instance) {41var div = document.createElement('div');42// None of our tests actually require attaching the container to the43// DOM, and doing so creates a mess that we rely on test isolation to44// clean up, so we're going to stop honoring the name of this method45// (and probably rename it eventually) if no problems arise.46// document.documentElement.appendChild(div);47return React.render(instance, div);48},4950isElement: function(element) {51return ReactElement.isValidElement(element);52},5354isElementOfType: function(inst, convenienceConstructor) {55return (56ReactElement.isValidElement(inst) &&57inst.type === convenienceConstructor.type58);59},6061isDOMComponent: function(inst) {62return !!(inst && inst.mountComponent && inst.tagName);63},6465isDOMComponentElement: function(inst) {66return !!(inst &&67ReactElement.isValidElement(inst) &&68!!inst.tagName);69},7071isCompositeComponent: function(inst) {72return typeof inst.render === 'function' &&73typeof inst.setState === 'function';74},7576isCompositeComponentWithType: function(inst, type) {77return !!(ReactTestUtils.isCompositeComponent(inst) &&78(inst.constructor === type.type));79},8081isCompositeComponentElement: function(inst) {82if (!ReactElement.isValidElement(inst)) {83return false;84}85// We check the prototype of the type that will get mounted, not the86// instance itself. This is a future proof way of duck typing.87var prototype = inst.type.prototype;88return (89typeof prototype.render === 'function' &&90typeof prototype.setState === 'function'91);92},9394isCompositeComponentElementWithType: function(inst, type) {95return !!(ReactTestUtils.isCompositeComponentElement(inst) &&96(inst.constructor === type));97},9899isTextComponent: function(inst) {100return inst instanceof ReactTextComponent.type;101},102103findAllInRenderedTree: function(inst, test) {104if (!inst) {105return [];106}107var ret = test(inst) ? [inst] : [];108if (ReactTestUtils.isDOMComponent(inst)) {109var renderedChildren = inst._renderedChildren;110var key;111for (key in renderedChildren) {112if (!renderedChildren.hasOwnProperty(key)) {113continue;114}115ret = ret.concat(116ReactTestUtils.findAllInRenderedTree(renderedChildren[key], test)117);118}119} else if (ReactTestUtils.isCompositeComponent(inst)) {120ret = ret.concat(121ReactTestUtils.findAllInRenderedTree(inst._renderedComponent, test)122);123}124return ret;125},126127/**128* Finds all instance of components in the rendered tree that are DOM129* components with the class name matching `className`.130* @return an array of all the matches.131*/132scryRenderedDOMComponentsWithClass: function(root, className) {133return ReactTestUtils.findAllInRenderedTree(root, function(inst) {134var instClassName = inst.props.className;135return ReactTestUtils.isDOMComponent(inst) && (136instClassName &&137(' ' + instClassName + ' ').indexOf(' ' + className + ' ') !== -1138);139});140},141142/**143* Like scryRenderedDOMComponentsWithClass but expects there to be one result,144* and returns that one result, or throws exception if there is any other145* number of matches besides one.146* @return {!ReactDOMComponent} The one match.147*/148findRenderedDOMComponentWithClass: function(root, className) {149var all =150ReactTestUtils.scryRenderedDOMComponentsWithClass(root, className);151if (all.length !== 1) {152throw new Error('Did not find exactly one match for class:' + className);153}154return all[0];155},156157158/**159* Finds all instance of components in the rendered tree that are DOM160* components with the tag name matching `tagName`.161* @return an array of all the matches.162*/163scryRenderedDOMComponentsWithTag: function(root, tagName) {164return ReactTestUtils.findAllInRenderedTree(root, function(inst) {165return ReactTestUtils.isDOMComponent(inst) &&166inst.tagName === tagName.toUpperCase();167});168},169170/**171* Like scryRenderedDOMComponentsWithTag but expects there to be one result,172* and returns that one result, or throws exception if there is any other173* number of matches besides one.174* @return {!ReactDOMComponent} The one match.175*/176findRenderedDOMComponentWithTag: function(root, tagName) {177var all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName);178if (all.length !== 1) {179throw new Error('Did not find exactly one match for tag:' + tagName);180}181return all[0];182},183184185/**186* Finds all instances of components with type equal to `componentType`.187* @return an array of all the matches.188*/189scryRenderedComponentsWithType: function(root, componentType) {190return ReactTestUtils.findAllInRenderedTree(root, function(inst) {191return ReactTestUtils.isCompositeComponentWithType(192inst,193componentType194);195});196},197198/**199* Same as `scryRenderedComponentsWithType` but expects there to be one result200* and returns that one result, or throws exception if there is any other201* number of matches besides one.202* @return {!ReactComponent} The one match.203*/204findRenderedComponentWithType: function(root, componentType) {205var all = ReactTestUtils.scryRenderedComponentsWithType(206root,207componentType208);209if (all.length !== 1) {210throw new Error(211'Did not find exactly one match for componentType:' + componentType212);213}214return all[0];215},216217/**218* Pass a mocked component module to this method to augment it with219* useful methods that allow it to be used as a dummy React component.220* Instead of rendering as usual, the component will become a simple221* <div> containing any provided children.222*223* @param {object} module the mock function object exported from a224* module that defines the component to be mocked225* @param {?string} mockTagName optional dummy root tag name to return226* from render method (overrides227* module.mockTagName if provided)228* @return {object} the ReactTestUtils object (for chaining)229*/230mockComponent: function(module, mockTagName) {231mockTagName = mockTagName || module.mockTagName || "div";232233var ConvenienceConstructor = React.createClass({234render: function() {235return React.createElement(236mockTagName,237null,238this.props.children239);240}241});242243module.mockImplementation(ConvenienceConstructor);244245module.type = ConvenienceConstructor.type;246module.isReactLegacyFactory = true;247248return this;249},250251/**252* Simulates a top level event being dispatched from a raw event that occured253* on an `Element` node.254* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`255* @param {!Element} node The dom to simulate an event occurring on.256* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.257*/258simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {259fakeNativeEvent.target = node;260ReactBrowserEventEmitter.ReactEventListener.dispatchEvent(261topLevelType,262fakeNativeEvent263);264},265266/**267* Simulates a top level event being dispatched from a raw event that occured268* on the `ReactDOMComponent` `comp`.269* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`.270* @param comp {!ReactDOMComponent}271* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.272*/273simulateNativeEventOnDOMComponent: function(274topLevelType,275comp,276fakeNativeEvent) {277ReactTestUtils.simulateNativeEventOnNode(278topLevelType,279comp.getDOMNode(),280fakeNativeEvent281);282},283284nativeTouchData: function(x, y) {285return {286touches: [287{pageX: x, pageY: y}288]289};290},291292Simulate: null,293SimulateNative: {}294};295296/**297* Exports:298*299* - `ReactTestUtils.Simulate.click(Element/ReactDOMComponent)`300* - `ReactTestUtils.Simulate.mouseMove(Element/ReactDOMComponent)`301* - `ReactTestUtils.Simulate.change(Element/ReactDOMComponent)`302* - ... (All keys from event plugin `eventTypes` objects)303*/304function makeSimulator(eventType) {305return function(domComponentOrNode, eventData) {306var node;307if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {308node = domComponentOrNode.getDOMNode();309} else if (domComponentOrNode.tagName) {310node = domComponentOrNode;311}312313var fakeNativeEvent = new Event();314fakeNativeEvent.target = node;315// We don't use SyntheticEvent.getPooled in order to not have to worry about316// properly destroying any properties assigned from `eventData` upon release317var event = new SyntheticEvent(318ReactBrowserEventEmitter.eventNameDispatchConfigs[eventType],319ReactMount.getID(node),320fakeNativeEvent321);322assign(event, eventData);323EventPropagators.accumulateTwoPhaseDispatches(event);324325ReactUpdates.batchedUpdates(function() {326EventPluginHub.enqueueEvents(event);327EventPluginHub.processEventQueue();328});329};330}331332function buildSimulators() {333ReactTestUtils.Simulate = {};334335var eventType;336for (eventType in ReactBrowserEventEmitter.eventNameDispatchConfigs) {337/**338* @param {!Element || ReactDOMComponent} domComponentOrNode339* @param {?object} eventData Fake event data to use in SyntheticEvent.340*/341ReactTestUtils.Simulate[eventType] = makeSimulator(eventType);342}343}344345// Rebuild ReactTestUtils.Simulate whenever event plugins are injected346var oldInjectEventPluginOrder = EventPluginHub.injection.injectEventPluginOrder;347EventPluginHub.injection.injectEventPluginOrder = function() {348oldInjectEventPluginOrder.apply(this, arguments);349buildSimulators();350};351var oldInjectEventPlugins = EventPluginHub.injection.injectEventPluginsByName;352EventPluginHub.injection.injectEventPluginsByName = function() {353oldInjectEventPlugins.apply(this, arguments);354buildSimulators();355};356357buildSimulators();358359/**360* Exports:361*362* - `ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent)`363* - `ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent)`364* - `ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent)`365* - `ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent)`366* - ... (All keys from `EventConstants.topLevelTypes`)367*368* Note: Top level event types are a subset of the entire set of handler types369* (which include a broader set of "synthetic" events). For example, onDragDone370* is a synthetic event. Except when testing an event plugin or React's event371* handling code specifically, you probably want to use ReactTestUtils.Simulate372* to dispatch synthetic events.373*/374375function makeNativeSimulator(eventType) {376return function(domComponentOrNode, nativeEventData) {377var fakeNativeEvent = new Event(eventType);378assign(fakeNativeEvent, nativeEventData);379if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {380ReactTestUtils.simulateNativeEventOnDOMComponent(381eventType,382domComponentOrNode,383fakeNativeEvent384);385} else if (!!domComponentOrNode.tagName) {386// Will allow on actual dom nodes.387ReactTestUtils.simulateNativeEventOnNode(388eventType,389domComponentOrNode,390fakeNativeEvent391);392}393};394}395396var eventType;397for (eventType in topLevelTypes) {398// Event type is stored as 'topClick' - we transform that to 'click'399var convenienceName = eventType.indexOf('top') === 0 ?400eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;401/**402* @param {!Element || ReactDOMComponent} domComponentOrNode403* @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.404*/405ReactTestUtils.SimulateNative[convenienceName] =406makeNativeSimulator(eventType);407}408409module.exports = ReactTestUtils;410411412