import * as React from 'react' ; export type AnyElement = string | React . ComponentType < any > ; export type ElementMatcher = AnyElement | RegExp ; export type PartialMockedElement = { type ? : AnyElement ; props ? : any ; children ? : any [ ] ; } ; export type Matcher = ( type : ElementMatcher , props : any , children ? : any [ ] ) => boolean ; export type Mocker = ( type : AnyElement , props ? : any , children ? : any [ ] ) => undefined | PartialMockedElement | React . ReactElement < any > ; export type Unsubscribe = ( ) => void ; export interface Mock { test : Matcher ; replace : Mocker ; } let matchers = [ ] ; let matcherStack = [ ] ; const getNameOf = ( type ) : string => { if ( ! type ) return 'Unknown' ; if ( typeof type === 'string' ) return type ; return type . displayName || type . name || 'Component' ; } ; const realAddMock = ( mock ) : Unsubscribe => { matchers . push ( mock ) ; return ( ) => matchers = matchers . filter ( el => el !== mock ) ; } ; const MockedOut = ( ) => null ; const MockedTransparent = ( { children } ) => children as any ; const defaultMock = ( type , props ) => ( { type : MockedOut , props : { itWas : getNameOf ( type ) , ... props } } ) ; const returnNull = ( ) : null => null ; const isRegExp = ( exp ) => exp && exp . constructor === RegExp ; const mock = ( type , mockBy ? ) : Unsubscribe => { const mock = { test : ( element ) => { const elementName = getNameOf ( element ) ; return element === type || ( typeof type !== 'function' && ( elementName === type || ( isRegExp ( type ) && ! ! elementName . match ( type ) ) ) ) ; } , replace : typeof mockBy === 'undefined' ? defaultMock : ( mockBy || returnNull ) } ; return realAddMock ( mock ) ; } ; const match = ( match , mockBy ? ) : Unsubscribe => { const mock = { test : match , replace : mockBy || defaultMock } ; return realAddMock ( mock ) ; } ; const transparent = ( type ) : Unsubscribe => { return mock ( type , ( ) => ( { type : MockedTransparent } ) ) ; } ; const renderProp = ( type , ... args ) : Unsubscribe => { return mock ( type , ( type , props , _children ) => { const children = Array . isArray ( _children ) ? _children [ 0 ] : _children ; if ( typeof children !== "function" ) { console . error ( 'remock: mocked' , type , ' expects' , children , ' to be a function (it is ' , typeof children , ')' ) ; return { } ; } return { type : MockedTransparent , props : { itWas : getNameOf ( type ) , ... props , } , children : ( children as any ) ( ... args ) } ; } ) ; } ; const unmock = ( type , props ? ) => { matchers = matchers . filter ( mock => ! mock . test ( type , props ) ) ; } ; const clearMocks = ( ) => { matchers = [ ] ; } ; const push = ( ) => { matcherStack . push ( [ ... matchers ] ) ; } ; const pop = ( ) => { matchers = matcherStack . pop ( ) ; } ; const getMocks = ( ) => matchers ; export { mock , match , unmock , transparent , renderProp , clearMocks , push , pop , getMocks } ;