2017-12-10 21:51:33 +01:00
/ * * @ l i c e n s e R e a c t v 1 6 . 2 . 0
2017-10-14 18:40:54 +02:00
* react - dom - test - utils . development . js
*
* Copyright ( c ) 2013 - present , Facebook , Inc .
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree .
* /
2017-12-10 21:51:33 +01:00
2017-10-14 18:40:54 +02:00
'use strict' ;
2017-12-10 21:51:33 +01:00
if ( process . env . NODE _ENV !== "production" ) {
( function ( ) {
2017-10-14 18:40:54 +02:00
'use strict' ;
var _assign = require ( 'object-assign' ) ;
2017-12-10 21:51:33 +01:00
var React = require ( 'react' ) ;
var ReactDOM = require ( 'react-dom' ) ;
2017-10-14 18:40:54 +02:00
var invariant = require ( 'fbjs/lib/invariant' ) ;
var warning = require ( 'fbjs/lib/warning' ) ;
var emptyFunction = require ( 'fbjs/lib/emptyFunction' ) ;
2017-12-10 21:51:33 +01:00
var ExecutionEnvironment = require ( 'fbjs/lib/ExecutionEnvironment' ) ;
2017-10-14 18:40:54 +02:00
/ * *
2017-12-10 21:51:33 +01:00
* WARNING : DO NOT manually require this module .
* This is a replacement for ` invariant(...) ` used by the error code system
* and will _only _ be required by the corresponding babel pass .
* It always throws .
2017-10-14 18:40:54 +02:00
* /
/ * *
* ` ReactInstanceMap ` maintains a mapping from a public facing stateful
* instance ( key ) and the internal representation ( value ) . This allows public
* methods to accept the user facing instance as an argument and map them back
* to internal methods .
*
2017-12-10 21:51:33 +01:00
* Note that this module is currently shared and assumed to be stateless .
* If this becomes an actual Map , that will break .
2017-10-14 18:40:54 +02:00
* /
/ * *
2017-12-10 21:51:33 +01:00
* This API should be called ` delete ` but we ' d have to make sure to always
* transform these to strings for IE support . When this transform is fully
* supported we can rename it .
2017-10-14 18:40:54 +02:00
* /
2017-12-10 21:51:33 +01:00
function get ( key ) {
return key . _reactInternalFiber ;
2017-10-14 18:40:54 +02:00
}
2017-12-10 21:51:33 +01:00
var ReactInternals = React . _ _SECRET _INTERNALS _DO _NOT _USE _OR _YOU _WILL _BE _FIRED ;
var ReactCurrentOwner = ReactInternals . ReactCurrentOwner ;
var ReactDebugCurrentFrame = ReactInternals . ReactDebugCurrentFrame ;
// Before we know whether it is functional or class
var FunctionalComponent = 1 ;
var ClassComponent = 2 ;
var HostRoot = 3 ; // Root of a host tree. Could be nested inside another node.
// A subtree. Could be an entry point to a different renderer.
var HostComponent = 5 ;
var HostText = 6 ;
// Don't change these two values:
var NoEffect = 0 ; // 0b00000000
// 0b00000001
// You can change the rest (and add more).
var Placement = 2 ; // 0b00000010
// 0b00000100
// 0b00000110
// 0b00001000
// 0b00010000
// 0b00100000
// 0b01000000
// 0b10000000
2017-10-14 18:40:54 +02:00
var MOUNTING = 1 ;
var MOUNTED = 2 ;
var UNMOUNTED = 3 ;
function isFiberMountedImpl ( fiber ) {
var node = fiber ;
if ( ! fiber . alternate ) {
// If there is no alternate, this might be a new tree that isn't inserted
// yet. If it is, then it will have a pending insertion effect on it.
if ( ( node . effectTag & Placement ) !== NoEffect ) {
return MOUNTING ;
}
while ( node [ 'return' ] ) {
node = node [ 'return' ] ;
if ( ( node . effectTag & Placement ) !== NoEffect ) {
return MOUNTING ;
}
}
} else {
while ( node [ 'return' ] ) {
node = node [ 'return' ] ;
}
}
if ( node . tag === HostRoot ) {
// TODO: Check if this was a nested HostRoot when used with
// renderContainerIntoSubtree.
return MOUNTED ;
}
// If we didn't hit the root, that means that we're in an disconnected tree
// that has been unmounted.
return UNMOUNTED ;
}
2017-12-10 21:51:33 +01:00
2017-10-14 18:40:54 +02:00
function assertIsMounted ( fiber ) {
! ( isFiberMountedImpl ( fiber ) === MOUNTED ) ? invariant ( false , 'Unable to find node on an unmounted component.' ) : void 0 ;
}
function findCurrentFiberUsingSlowPath ( fiber ) {
var alternate = fiber . alternate ;
if ( ! alternate ) {
// If there is no alternate, then we only need to check if it is mounted.
var state = isFiberMountedImpl ( fiber ) ;
! ( state !== UNMOUNTED ) ? invariant ( false , 'Unable to find node on an unmounted component.' ) : void 0 ;
if ( state === MOUNTING ) {
return null ;
}
return fiber ;
}
// If we have two possible branches, we'll walk backwards up to the root
// to see what path the root points to. On the way we may hit one of the
// special cases and we'll deal with them.
var a = fiber ;
var b = alternate ;
while ( true ) {
var parentA = a [ 'return' ] ;
var parentB = parentA ? parentA . alternate : null ;
if ( ! parentA || ! parentB ) {
// We're at the root.
break ;
}
// If both copies of the parent fiber point to the same child, we can
// assume that the child is current. This happens when we bailout on low
// priority: the bailed out fiber's child reuses the current child.
if ( parentA . child === parentB . child ) {
var child = parentA . child ;
while ( child ) {
if ( child === a ) {
// We've determined that A is the current branch.
assertIsMounted ( parentA ) ;
return fiber ;
}
if ( child === b ) {
// We've determined that B is the current branch.
assertIsMounted ( parentA ) ;
return alternate ;
}
child = child . sibling ;
}
// We should never have an alternate for any mounting node. So the only
// way this could possibly happen is if this was unmounted, if at all.
invariant ( false , 'Unable to find node on an unmounted component.' ) ;
}
if ( a [ 'return' ] !== b [ 'return' ] ) {
// The return pointer of A and the return pointer of B point to different
// fibers. We assume that return pointers never criss-cross, so A must
// belong to the child set of A.return, and B must belong to the child
// set of B.return.
a = parentA ;
b = parentB ;
} else {
// The return pointers point to the same fiber. We'll have to use the
// default, slow path: scan the child sets of each parent alternate to see
// which child belongs to which set.
//
// Search parent A's child set
var didFindChild = false ;
var _child = parentA . child ;
while ( _child ) {
if ( _child === a ) {
didFindChild = true ;
a = parentA ;
b = parentB ;
break ;
}
if ( _child === b ) {
didFindChild = true ;
b = parentA ;
a = parentB ;
break ;
}
_child = _child . sibling ;
}
if ( ! didFindChild ) {
// Search parent B's child set
_child = parentB . child ;
while ( _child ) {
if ( _child === a ) {
didFindChild = true ;
a = parentB ;
b = parentA ;
break ;
}
if ( _child === b ) {
didFindChild = true ;
b = parentB ;
a = parentA ;
break ;
}
_child = _child . sibling ;
}
! didFindChild ? invariant ( false , 'Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.' ) : void 0 ;
}
}
! ( a . alternate === b ) ? invariant ( false , 'Return fibers should always be each others\' alternates. This error is likely caused by a bug in React. Please file an issue.' ) : void 0 ;
}
// If the root is not a host container, we're in a disconnected tree. I.e.
// unmounted.
! ( a . tag === HostRoot ) ? invariant ( false , 'Unable to find node on an unmounted component.' ) : void 0 ;
if ( a . stateNode . current === a ) {
// We've determined that A is the current branch.
return fiber ;
}
// Otherwise B has to be current branch.
return alternate ;
}
2017-12-10 21:51:33 +01:00
/* eslint valid-typeof: 0 */
2017-10-14 18:40:54 +02:00
var didWarnForAddedNewProperty = false ;
var isProxySupported = typeof Proxy === 'function' ;
var EVENT _POOL _SIZE = 10 ;
var shouldBeReleasedProperties = [ 'dispatchConfig' , '_targetInst' , 'nativeEvent' , 'isDefaultPrevented' , 'isPropagationStopped' , '_dispatchListeners' , '_dispatchInstances' ] ;
/ * *
* @ interface Event
* @ see http : //www.w3.org/TR/DOM-Level-3-Events/
* /
var EventInterface = {
type : null ,
target : null ,
// currentTarget is set when dispatching; no use in copying it here
currentTarget : emptyFunction . thatReturnsNull ,
eventPhase : null ,
bubbles : null ,
cancelable : null ,
timeStamp : function ( event ) {
return event . timeStamp || Date . now ( ) ;
} ,
defaultPrevented : null ,
isTrusted : null
} ;
/ * *
* Synthetic events are dispatched by event plugins , typically in response to a
* top - level event delegation handler .
*
* These systems should generally use pooling to reduce the frequency of garbage
* collection . The system should check ` isPersistent ` to determine whether the
* event should be released into the pool after being dispatched . Users that
* need a persisted event should invoke ` persist ` .
*
* Synthetic events ( and subclasses ) implement the DOM Level 3 Events API by
* normalizing browser quirks . Subclasses do not necessarily have to implement a
* DOM interface ; custom application - specific events can also subclass this .
*
* @ param { object } dispatchConfig Configuration used to dispatch this event .
* @ param { * } targetInst Marker identifying the event target .
* @ param { object } nativeEvent Native browser event .
* @ param { DOMEventTarget } nativeEventTarget Target node .
* /
function SyntheticEvent ( dispatchConfig , targetInst , nativeEvent , nativeEventTarget ) {
{
// these have a getter/setter for warnings
delete this . nativeEvent ;
delete this . preventDefault ;
delete this . stopPropagation ;
}
this . dispatchConfig = dispatchConfig ;
this . _targetInst = targetInst ;
this . nativeEvent = nativeEvent ;
var Interface = this . constructor . Interface ;
for ( var propName in Interface ) {
if ( ! Interface . hasOwnProperty ( propName ) ) {
continue ;
}
{
delete this [ propName ] ; // this has a getter/setter for warnings
}
var normalize = Interface [ propName ] ;
if ( normalize ) {
this [ propName ] = normalize ( nativeEvent ) ;
} else {
if ( propName === 'target' ) {
this . target = nativeEventTarget ;
} else {
this [ propName ] = nativeEvent [ propName ] ;
}
}
}
var defaultPrevented = nativeEvent . defaultPrevented != null ? nativeEvent . defaultPrevented : nativeEvent . returnValue === false ;
if ( defaultPrevented ) {
this . isDefaultPrevented = emptyFunction . thatReturnsTrue ;
} else {
this . isDefaultPrevented = emptyFunction . thatReturnsFalse ;
}
this . isPropagationStopped = emptyFunction . thatReturnsFalse ;
return this ;
}
_assign ( SyntheticEvent . prototype , {
preventDefault : function ( ) {
this . defaultPrevented = true ;
var event = this . nativeEvent ;
if ( ! event ) {
return ;
}
if ( event . preventDefault ) {
event . preventDefault ( ) ;
} else if ( typeof event . returnValue !== 'unknown' ) {
event . returnValue = false ;
}
this . isDefaultPrevented = emptyFunction . thatReturnsTrue ;
} ,
stopPropagation : function ( ) {
var event = this . nativeEvent ;
if ( ! event ) {
return ;
}
if ( event . stopPropagation ) {
event . stopPropagation ( ) ;
} else if ( typeof event . cancelBubble !== 'unknown' ) {
// The ChangeEventPlugin registers a "propertychange" event for
// IE. This event does not support bubbling or cancelling, and
// any references to cancelBubble throw "Member not found". A
// typeof check of "unknown" circumvents this issue (and is also
// IE specific).
event . cancelBubble = true ;
}
this . isPropagationStopped = emptyFunction . thatReturnsTrue ;
} ,
/ * *
* We release all dispatched ` SyntheticEvent ` s after each event loop , adding
* them back into the pool . This allows a way to hold onto a reference that
* won ' t be added back into the pool .
* /
persist : function ( ) {
this . isPersistent = emptyFunction . thatReturnsTrue ;
} ,
/ * *
* Checks if this event should be released back into the pool .
*
* @ return { boolean } True if this should not be released , false otherwise .
* /
isPersistent : emptyFunction . thatReturnsFalse ,
/ * *
* ` PooledClass ` looks for ` destructor ` on each instance it releases .
* /
destructor : function ( ) {
var Interface = this . constructor . Interface ;
for ( var propName in Interface ) {
{
Object . defineProperty ( this , propName , getPooledWarningPropertyDefinition ( propName , Interface [ propName ] ) ) ;
}
}
for ( var i = 0 ; i < shouldBeReleasedProperties . length ; i ++ ) {
this [ shouldBeReleasedProperties [ i ] ] = null ;
}
{
Object . defineProperty ( this , 'nativeEvent' , getPooledWarningPropertyDefinition ( 'nativeEvent' , null ) ) ;
Object . defineProperty ( this , 'preventDefault' , getPooledWarningPropertyDefinition ( 'preventDefault' , emptyFunction ) ) ;
Object . defineProperty ( this , 'stopPropagation' , getPooledWarningPropertyDefinition ( 'stopPropagation' , emptyFunction ) ) ;
}
}
} ) ;
SyntheticEvent . Interface = EventInterface ;
/ * *
* Helper to reduce boilerplate when creating subclasses .
*
* @ param { function } Class
* @ param { ? object } Interface
* /
SyntheticEvent . augmentClass = function ( Class , Interface ) {
var Super = this ;
var E = function ( ) { } ;
E . prototype = Super . prototype ;
var prototype = new E ( ) ;
_assign ( prototype , Class . prototype ) ;
Class . prototype = prototype ;
Class . prototype . constructor = Class ;
Class . Interface = _assign ( { } , Super . Interface , Interface ) ;
Class . augmentClass = Super . augmentClass ;
addEventPoolingTo ( Class ) ;
} ;
/ * * P r o x y i n g a f t e r e v e r y t h i n g s e t o n S y n t h e t i c E v e n t
2017-12-10 21:51:33 +01:00
* to resolve Proxy issue on some WebKit browsers
* in which some Event properties are set to undefined ( GH # 10010 )
* /
2017-10-14 18:40:54 +02:00
{
if ( isProxySupported ) {
/*eslint-disable no-func-assign */
SyntheticEvent = new Proxy ( SyntheticEvent , {
construct : function ( target , args ) {
return this . apply ( target , Object . create ( target . prototype ) , args ) ;
} ,
apply : function ( constructor , that , args ) {
return new Proxy ( constructor . apply ( that , args ) , {
set : function ( target , prop , value ) {
if ( prop !== 'isPersistent' && ! target . constructor . Interface . hasOwnProperty ( prop ) && shouldBeReleasedProperties . indexOf ( prop ) === - 1 ) {
2017-12-10 21:51:33 +01:00
warning ( didWarnForAddedNewProperty || target . isPersistent ( ) , "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.' ) ;
2017-10-14 18:40:54 +02:00
didWarnForAddedNewProperty = true ;
}
target [ prop ] = value ;
return true ;
}
} ) ;
}
} ) ;
/*eslint-enable no-func-assign */
}
}
addEventPoolingTo ( SyntheticEvent ) ;
/ * *
2017-12-10 21:51:33 +01:00
* Helper to nullify syntheticEvent instance properties when destructing
*
* @ param { String } propName
* @ param { ? object } getVal
* @ return { object } defineProperty object
* /
2017-10-14 18:40:54 +02:00
function getPooledWarningPropertyDefinition ( propName , getVal ) {
var isFunction = typeof getVal === 'function' ;
return {
configurable : true ,
set : set ,
get : get
} ;
function set ( val ) {
var action = isFunction ? 'setting the method' : 'setting the property' ;
warn ( action , 'This is effectively a no-op' ) ;
return val ;
}
function get ( ) {
var action = isFunction ? 'accessing the method' : 'accessing the property' ;
var result = isFunction ? 'This is a no-op function' : 'This is set to null' ;
warn ( action , result ) ;
return getVal ;
}
function warn ( action , result ) {
var warningCondition = false ;
2017-12-10 21:51:33 +01:00
warning ( warningCondition , "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.' , action , propName , result ) ;
2017-10-14 18:40:54 +02:00
}
}
function getPooledEvent ( dispatchConfig , targetInst , nativeEvent , nativeInst ) {
var EventConstructor = this ;
if ( EventConstructor . eventPool . length ) {
var instance = EventConstructor . eventPool . pop ( ) ;
EventConstructor . call ( instance , dispatchConfig , targetInst , nativeEvent , nativeInst ) ;
return instance ;
}
return new EventConstructor ( dispatchConfig , targetInst , nativeEvent , nativeInst ) ;
}
function releasePooledEvent ( event ) {
var EventConstructor = this ;
! ( event instanceof EventConstructor ) ? invariant ( false , 'Trying to release an event instance into a pool of a different type.' ) : void 0 ;
event . destructor ( ) ;
if ( EventConstructor . eventPool . length < EVENT _POOL _SIZE ) {
EventConstructor . eventPool . push ( event ) ;
}
}
function addEventPoolingTo ( EventConstructor ) {
EventConstructor . eventPool = [ ] ;
EventConstructor . getPooled = getPooledEvent ;
EventConstructor . release = releasePooledEvent ;
}
2017-12-10 21:51:33 +01:00
var SyntheticEvent$1 = SyntheticEvent ;
/ * *
* Generate a mapping of standard vendor prefixes using the defined style property and event name .
*
* @ param { string } styleProp
* @ param { string } eventName
* @ returns { object }
* /
function makePrefixMap ( styleProp , eventName ) {
var prefixes = { } ;
prefixes [ styleProp . toLowerCase ( ) ] = eventName . toLowerCase ( ) ;
prefixes [ 'Webkit' + styleProp ] = 'webkit' + eventName ;
prefixes [ 'Moz' + styleProp ] = 'moz' + eventName ;
prefixes [ 'ms' + styleProp ] = 'MS' + eventName ;
prefixes [ 'O' + styleProp ] = 'o' + eventName . toLowerCase ( ) ;
return prefixes ;
}
/ * *
* A list of event names to a configurable list of vendor prefixes .
* /
var vendorPrefixes = {
animationend : makePrefixMap ( 'Animation' , 'AnimationEnd' ) ,
animationiteration : makePrefixMap ( 'Animation' , 'AnimationIteration' ) ,
animationstart : makePrefixMap ( 'Animation' , 'AnimationStart' ) ,
transitionend : makePrefixMap ( 'Transition' , 'TransitionEnd' )
} ;
/ * *
* Event names that have already been detected and prefixed ( if applicable ) .
* /
var prefixedEventNames = { } ;
/ * *
* Element to check for prefixes on .
* /
var style = { } ;
/ * *
* Bootstrap if a DOM exists .
* /
if ( ExecutionEnvironment . canUseDOM ) {
style = document . createElement ( 'div' ) . style ;
// On some platforms, in particular some releases of Android 4.x,
// the un-prefixed "animation" and "transition" properties are defined on the
// style object but the events that fire will still be prefixed, so we need
// to check if the un-prefixed events are usable, and if not remove them from the map.
if ( ! ( 'AnimationEvent' in window ) ) {
delete vendorPrefixes . animationend . animation ;
delete vendorPrefixes . animationiteration . animation ;
delete vendorPrefixes . animationstart . animation ;
}
// Same as above
if ( ! ( 'TransitionEvent' in window ) ) {
delete vendorPrefixes . transitionend . transition ;
}
}
/ * *
* Attempts to determine the correct vendor prefixed event name .
*
* @ param { string } eventName
* @ returns { string }
* /
function getVendorPrefixedEventName ( eventName ) {
if ( prefixedEventNames [ eventName ] ) {
return prefixedEventNames [ eventName ] ;
} else if ( ! vendorPrefixes [ eventName ] ) {
return eventName ;
}
var prefixMap = vendorPrefixes [ eventName ] ;
for ( var styleProp in prefixMap ) {
if ( prefixMap . hasOwnProperty ( styleProp ) && styleProp in style ) {
return prefixedEventNames [ eventName ] = prefixMap [ styleProp ] ;
}
}
return '' ;
}
/ * *
* Types of raw signals from the browser caught at the top level .
*
* For events like 'submit' which don ' t consistently bubble ( which we
* trap at a lower node than ` document ` ) , binding at ` document ` would
* cause duplicate events so we don ' t include them here .
* /
var topLevelTypes$1 = {
topAbort : 'abort' ,
topAnimationEnd : getVendorPrefixedEventName ( 'animationend' ) || 'animationend' ,
topAnimationIteration : getVendorPrefixedEventName ( 'animationiteration' ) || 'animationiteration' ,
topAnimationStart : getVendorPrefixedEventName ( 'animationstart' ) || 'animationstart' ,
topBlur : 'blur' ,
topCancel : 'cancel' ,
topCanPlay : 'canplay' ,
topCanPlayThrough : 'canplaythrough' ,
topChange : 'change' ,
topClick : 'click' ,
topClose : 'close' ,
topCompositionEnd : 'compositionend' ,
topCompositionStart : 'compositionstart' ,
topCompositionUpdate : 'compositionupdate' ,
topContextMenu : 'contextmenu' ,
topCopy : 'copy' ,
topCut : 'cut' ,
topDoubleClick : 'dblclick' ,
topDrag : 'drag' ,
topDragEnd : 'dragend' ,
topDragEnter : 'dragenter' ,
topDragExit : 'dragexit' ,
topDragLeave : 'dragleave' ,
topDragOver : 'dragover' ,
topDragStart : 'dragstart' ,
topDrop : 'drop' ,
topDurationChange : 'durationchange' ,
topEmptied : 'emptied' ,
topEncrypted : 'encrypted' ,
topEnded : 'ended' ,
topError : 'error' ,
topFocus : 'focus' ,
topInput : 'input' ,
topKeyDown : 'keydown' ,
topKeyPress : 'keypress' ,
topKeyUp : 'keyup' ,
topLoadedData : 'loadeddata' ,
topLoad : 'load' ,
topLoadedMetadata : 'loadedmetadata' ,
topLoadStart : 'loadstart' ,
topMouseDown : 'mousedown' ,
topMouseMove : 'mousemove' ,
topMouseOut : 'mouseout' ,
topMouseOver : 'mouseover' ,
topMouseUp : 'mouseup' ,
topPaste : 'paste' ,
topPause : 'pause' ,
topPlay : 'play' ,
topPlaying : 'playing' ,
topProgress : 'progress' ,
topRateChange : 'ratechange' ,
topScroll : 'scroll' ,
topSeeked : 'seeked' ,
topSeeking : 'seeking' ,
topSelectionChange : 'selectionchange' ,
topStalled : 'stalled' ,
topSuspend : 'suspend' ,
topTextInput : 'textInput' ,
topTimeUpdate : 'timeupdate' ,
topToggle : 'toggle' ,
topTouchCancel : 'touchcancel' ,
topTouchEnd : 'touchend' ,
topTouchMove : 'touchmove' ,
topTouchStart : 'touchstart' ,
topTransitionEnd : getVendorPrefixedEventName ( 'transitionend' ) || 'transitionend' ,
topVolumeChange : 'volumechange' ,
topWaiting : 'waiting' ,
topWheel : 'wheel'
} ;
var BrowserEventConstants = {
topLevelTypes : topLevelTypes$1
} ;
var findDOMNode = ReactDOM . findDOMNode ;
var _ReactDOM$ _ _SECRET _IN = ReactDOM . _ _SECRET _INTERNALS _DO _NOT _USE _OR _YOU _WILL _BE _FIRED ;
2017-10-14 18:40:54 +02:00
var EventPluginHub = _ReactDOM$ _ _SECRET _IN . EventPluginHub ;
var EventPluginRegistry = _ReactDOM$ _ _SECRET _IN . EventPluginRegistry ;
var EventPropagators = _ReactDOM$ _ _SECRET _IN . EventPropagators ;
var ReactControlledComponent = _ReactDOM$ _ _SECRET _IN . ReactControlledComponent ;
var ReactDOMComponentTree = _ReactDOM$ _ _SECRET _IN . ReactDOMComponentTree ;
var ReactDOMEventListener = _ReactDOM$ _ _SECRET _IN . ReactDOMEventListener ;
2017-12-10 21:51:33 +01:00
var topLevelTypes = BrowserEventConstants . topLevelTypes ;
2017-10-14 18:40:54 +02:00
function Event ( suffix ) { }
/ * *
* @ class ReactTestUtils
* /
function findAllInRenderedFiberTreeInternal ( fiber , test ) {
if ( ! fiber ) {
return [ ] ;
}
2017-12-10 21:51:33 +01:00
var currentParent = findCurrentFiberUsingSlowPath ( fiber ) ;
2017-10-14 18:40:54 +02:00
if ( ! currentParent ) {
return [ ] ;
}
var node = currentParent ;
var ret = [ ] ;
while ( true ) {
if ( node . tag === HostComponent || node . tag === HostText || node . tag === ClassComponent || node . tag === FunctionalComponent ) {
var publicInst = node . stateNode ;
if ( test ( publicInst ) ) {
ret . push ( publicInst ) ;
}
}
if ( node . child ) {
node . child [ 'return' ] = node ;
node = node . child ;
continue ;
}
if ( node === currentParent ) {
return ret ;
}
while ( ! node . sibling ) {
if ( ! node [ 'return' ] || node [ 'return' ] === currentParent ) {
return ret ;
}
node = node [ 'return' ] ;
}
node . sibling [ 'return' ] = node [ 'return' ] ;
node = node . sibling ;
}
}
/ * *
* Utilities for making it easy to test React components .
*
2017-12-10 21:51:33 +01:00
* See https : //reactjs.org/docs/test-utils.html
2017-10-14 18:40:54 +02:00
*
* Todo : Support the entire DOM . scry query syntax . For now , these simple
* utilities will suffice for testing purposes .
* @ lends ReactTestUtils
* /
var ReactTestUtils = {
renderIntoDocument : function ( element ) {
var div = document . createElement ( 'div' ) ;
// None of our tests actually require attaching the container to the
// DOM, and doing so creates a mess that we rely on test isolation to
// clean up, so we're going to stop honoring the name of this method
// (and probably rename it eventually) if no problems arise.
// document.documentElement.appendChild(div);
2017-12-10 21:51:33 +01:00
return ReactDOM . render ( element , div ) ;
2017-10-14 18:40:54 +02:00
} ,
isElement : function ( element ) {
2017-12-10 21:51:33 +01:00
return React . isValidElement ( element ) ;
2017-10-14 18:40:54 +02:00
} ,
isElementOfType : function ( inst , convenienceConstructor ) {
2017-12-10 21:51:33 +01:00
return React . isValidElement ( inst ) && inst . type === convenienceConstructor ;
2017-10-14 18:40:54 +02:00
} ,
isDOMComponent : function ( inst ) {
return ! ! ( inst && inst . nodeType === 1 && inst . tagName ) ;
} ,
isDOMComponentElement : function ( inst ) {
2017-12-10 21:51:33 +01:00
return ! ! ( inst && React . isValidElement ( inst ) && ! ! inst . tagName ) ;
2017-10-14 18:40:54 +02:00
} ,
isCompositeComponent : function ( inst ) {
if ( ReactTestUtils . isDOMComponent ( inst ) ) {
// Accessing inst.setState warns; just return false as that'll be what
// this returns when we have DOM nodes as refs directly
return false ;
}
return inst != null && typeof inst . render === 'function' && typeof inst . setState === 'function' ;
} ,
isCompositeComponentWithType : function ( inst , type ) {
if ( ! ReactTestUtils . isCompositeComponent ( inst ) ) {
return false ;
}
2017-12-10 21:51:33 +01:00
var internalInstance = get ( inst ) ;
var constructor = internalInstance . type ;
2017-10-14 18:40:54 +02:00
return constructor === type ;
} ,
findAllInRenderedTree : function ( inst , test ) {
if ( ! inst ) {
return [ ] ;
}
! ReactTestUtils . isCompositeComponent ( inst ) ? invariant ( false , 'findAllInRenderedTree(...): instance must be a composite component' ) : void 0 ;
2017-12-10 21:51:33 +01:00
var internalInstance = get ( inst ) ;
return findAllInRenderedFiberTreeInternal ( internalInstance , test ) ;
2017-10-14 18:40:54 +02:00
} ,
/ * *
* Finds all instance of components in the rendered tree that are DOM
* components with the class name matching ` className ` .
* @ return { array } an array of all the matches .
* /
scryRenderedDOMComponentsWithClass : function ( root , classNames ) {
return ReactTestUtils . findAllInRenderedTree ( root , function ( inst ) {
if ( ReactTestUtils . isDOMComponent ( inst ) ) {
var className = inst . className ;
if ( typeof className !== 'string' ) {
// SVG, probably.
className = inst . getAttribute ( 'class' ) || '' ;
}
var classList = className . split ( /\s+/ ) ;
if ( ! Array . isArray ( classNames ) ) {
! ( classNames !== undefined ) ? invariant ( false , 'TestUtils.scryRenderedDOMComponentsWithClass expects a className as a second argument.' ) : void 0 ;
classNames = classNames . split ( /\s+/ ) ;
}
return classNames . every ( function ( name ) {
return classList . indexOf ( name ) !== - 1 ;
} ) ;
}
return false ;
} ) ;
} ,
/ * *
* Like scryRenderedDOMComponentsWithClass but expects there to be one result ,
* and returns that one result , or throws exception if there is any other
* number of matches besides one .
* @ return { ! ReactDOMComponent } The one match .
* /
findRenderedDOMComponentWithClass : function ( root , className ) {
var all = ReactTestUtils . scryRenderedDOMComponentsWithClass ( root , className ) ;
if ( all . length !== 1 ) {
throw new Error ( 'Did not find exactly one match (found: ' + all . length + ') ' + 'for class:' + className ) ;
}
return all [ 0 ] ;
} ,
/ * *
* Finds all instance of components in the rendered tree that are DOM
* components with the tag name matching ` tagName ` .
* @ return { array } an array of all the matches .
* /
scryRenderedDOMComponentsWithTag : function ( root , tagName ) {
return ReactTestUtils . findAllInRenderedTree ( root , function ( inst ) {
return ReactTestUtils . isDOMComponent ( inst ) && inst . tagName . toUpperCase ( ) === tagName . toUpperCase ( ) ;
} ) ;
} ,
/ * *
* Like scryRenderedDOMComponentsWithTag but expects there to be one result ,
* and returns that one result , or throws exception if there is any other
* number of matches besides one .
* @ return { ! ReactDOMComponent } The one match .
* /
findRenderedDOMComponentWithTag : function ( root , tagName ) {
var all = ReactTestUtils . scryRenderedDOMComponentsWithTag ( root , tagName ) ;
if ( all . length !== 1 ) {
throw new Error ( 'Did not find exactly one match (found: ' + all . length + ') ' + 'for tag:' + tagName ) ;
}
return all [ 0 ] ;
} ,
/ * *
* Finds all instances of components with type equal to ` componentType ` .
* @ return { array } an array of all the matches .
* /
scryRenderedComponentsWithType : function ( root , componentType ) {
return ReactTestUtils . findAllInRenderedTree ( root , function ( inst ) {
return ReactTestUtils . isCompositeComponentWithType ( inst , componentType ) ;
} ) ;
} ,
/ * *
* Same as ` scryRenderedComponentsWithType ` but expects there to be one result
* and returns that one result , or throws exception if there is any other
* number of matches besides one .
* @ return { ! ReactComponent } The one match .
* /
findRenderedComponentWithType : function ( root , componentType ) {
var all = ReactTestUtils . scryRenderedComponentsWithType ( root , componentType ) ;
if ( all . length !== 1 ) {
throw new Error ( 'Did not find exactly one match (found: ' + all . length + ') ' + 'for componentType:' + componentType ) ;
}
return all [ 0 ] ;
} ,
/ * *
* Pass a mocked component module to this method to augment it with
* useful methods that allow it to be used as a dummy React component .
* Instead of rendering as usual , the component will become a simple
* < div > containing any provided children .
*
* @ param { object } module the mock function object exported from a
* module that defines the component to be mocked
* @ param { ? string } mockTagName optional dummy root tag name to return
* from render method ( overrides
* module . mockTagName if provided )
* @ return { object } the ReactTestUtils object ( for chaining )
* /
mockComponent : function ( module , mockTagName ) {
mockTagName = mockTagName || module . mockTagName || 'div' ;
module . prototype . render . mockImplementation ( function ( ) {
2017-12-10 21:51:33 +01:00
return React . createElement ( mockTagName , null , this . props . children ) ;
2017-10-14 18:40:54 +02:00
} ) ;
return this ;
} ,
/ * *
* Simulates a top level event being dispatched from a raw event that occurred
* on an ` Element ` node .
* @ param { Object } topLevelType A type from ` BrowserEventConstants.topLevelTypes `
* @ param { ! Element } node The dom to simulate an event occurring on .
* @ param { ? Event } fakeNativeEvent Fake native event to use in SyntheticEvent .
* /
simulateNativeEventOnNode : function ( topLevelType , node , fakeNativeEvent ) {
fakeNativeEvent . target = node ;
ReactDOMEventListener . dispatchEvent ( topLevelType , fakeNativeEvent ) ;
} ,
/ * *
* Simulates a top level event being dispatched from a raw event that occurred
* on the ` ReactDOMComponent ` ` comp ` .
* @ param { Object } topLevelType A type from ` BrowserEventConstants.topLevelTypes ` .
* @ param { ! ReactDOMComponent } comp
* @ param { ? Event } fakeNativeEvent Fake native event to use in SyntheticEvent .
* /
simulateNativeEventOnDOMComponent : function ( topLevelType , comp , fakeNativeEvent ) {
ReactTestUtils . simulateNativeEventOnNode ( topLevelType , findDOMNode ( comp ) , fakeNativeEvent ) ;
} ,
nativeTouchData : function ( x , y ) {
return {
touches : [ { pageX : x , pageY : y } ]
} ;
} ,
Simulate : null ,
SimulateNative : { }
} ;
/ * *
* Exports :
*
* - ` ReactTestUtils.Simulate.click(Element) `
* - ` ReactTestUtils.Simulate.mouseMove(Element) `
* - ` ReactTestUtils.Simulate.change(Element) `
* - ... ( All keys from event plugin ` eventTypes ` objects )
* /
function makeSimulator ( eventType ) {
return function ( domNode , eventData ) {
2017-12-10 21:51:33 +01:00
! ! React . isValidElement ( domNode ) ? invariant ( false , 'TestUtils.Simulate expected a DOM node as the first argument but received a React element. Pass the DOM node you wish to simulate the event on instead. Note that TestUtils.Simulate will not work if you are using shallow rendering.' ) : void 0 ;
2017-10-14 18:40:54 +02:00
! ! ReactTestUtils . isCompositeComponent ( domNode ) ? invariant ( false , 'TestUtils.Simulate expected a DOM node as the first argument but received a component instance. Pass the DOM node you wish to simulate the event on instead.' ) : void 0 ;
var dispatchConfig = EventPluginRegistry . eventNameDispatchConfigs [ eventType ] ;
var fakeNativeEvent = new Event ( ) ;
fakeNativeEvent . target = domNode ;
fakeNativeEvent . type = eventType . toLowerCase ( ) ;
// We don't use SyntheticEvent.getPooled in order to not have to worry about
// properly destroying any properties assigned from `eventData` upon release
var targetInst = ReactDOMComponentTree . getInstanceFromNode ( domNode ) ;
2017-12-10 21:51:33 +01:00
var event = new SyntheticEvent$1 ( dispatchConfig , targetInst , fakeNativeEvent , domNode ) ;
2017-10-14 18:40:54 +02:00
// Since we aren't using pooling, always persist the event. This will make
// sure it's marked and won't warn when setting additional properties.
event . persist ( ) ;
_assign ( event , eventData ) ;
if ( dispatchConfig . phasedRegistrationNames ) {
EventPropagators . accumulateTwoPhaseDispatches ( event ) ;
} else {
EventPropagators . accumulateDirectDispatches ( event ) ;
}
2017-12-10 21:51:33 +01:00
ReactDOM . unstable _batchedUpdates ( function ( ) {
2017-10-14 18:40:54 +02:00
// Normally extractEvent enqueues a state restore, but we'll just always
// do that since we we're by-passing it here.
ReactControlledComponent . enqueueStateRestore ( domNode ) ;
EventPluginHub . enqueueEvents ( event ) ;
EventPluginHub . processEventQueue ( true ) ;
} ) ;
} ;
}
function buildSimulators ( ) {
ReactTestUtils . Simulate = { } ;
var eventType ;
for ( eventType in EventPluginRegistry . eventNameDispatchConfigs ) {
/ * *
* @ param { ! Element | ReactDOMComponent } domComponentOrNode
* @ param { ? object } eventData Fake event data to use in SyntheticEvent .
* /
ReactTestUtils . Simulate [ eventType ] = makeSimulator ( eventType ) ;
}
}
// Rebuild ReactTestUtils.Simulate whenever event plugins are injected
var oldInjectEventPluginOrder = EventPluginHub . injection . injectEventPluginOrder ;
EventPluginHub . injection . injectEventPluginOrder = function ( ) {
oldInjectEventPluginOrder . apply ( this , arguments ) ;
buildSimulators ( ) ;
} ;
var oldInjectEventPlugins = EventPluginHub . injection . injectEventPluginsByName ;
EventPluginHub . injection . injectEventPluginsByName = function ( ) {
oldInjectEventPlugins . apply ( this , arguments ) ;
buildSimulators ( ) ;
} ;
buildSimulators ( ) ;
/ * *
* Exports :
*
* - ` ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent) `
* - ` ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent) `
* - ` ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent) `
* - ` ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent) `
* - ... ( All keys from ` BrowserEventConstants.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 . 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 makeNativeSimulator ( eventType ) {
return function ( domComponentOrNode , nativeEventData ) {
var fakeNativeEvent = new Event ( eventType ) ;
_assign ( fakeNativeEvent , nativeEventData ) ;
if ( ReactTestUtils . isDOMComponent ( domComponentOrNode ) ) {
ReactTestUtils . simulateNativeEventOnDOMComponent ( eventType , domComponentOrNode , fakeNativeEvent ) ;
} else if ( domComponentOrNode . tagName ) {
// Will allow on actual dom nodes.
ReactTestUtils . simulateNativeEventOnNode ( eventType , domComponentOrNode , fakeNativeEvent ) ;
}
} ;
}
Object . keys ( topLevelTypes ) . forEach ( function ( eventType ) {
// Event type is stored as 'topClick' - we transform that to 'click'
var convenienceName = eventType . indexOf ( 'top' ) === 0 ? eventType . charAt ( 3 ) . toLowerCase ( ) + eventType . substr ( 4 ) : eventType ;
/ * *
* @ param { ! Element | ReactDOMComponent } domComponentOrNode
* @ param { ? Event } nativeEventData Fake native event to use in SyntheticEvent .
* /
ReactTestUtils . SimulateNative [ convenienceName ] = makeNativeSimulator ( eventType ) ;
} ) ;
2017-12-10 21:51:33 +01:00
var ReactTestUtils$2 = Object . freeze ( {
default : ReactTestUtils
} ) ;
var ReactTestUtils$3 = ( ReactTestUtils$2 && ReactTestUtils ) || ReactTestUtils$2 ;
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var testUtils = ReactTestUtils$3 [ 'default' ] ? ReactTestUtils$3 [ 'default' ] : ReactTestUtils$3 ;
module . exports = testUtils ;
} ) ( ) ;
2017-10-14 18:40:54 +02:00
}