import { configure , mount as enzymeMount , render as enzymeRender } from 'enzyme' ; import Adapter from 'enzyme-adapter-react-16' ; import * as React from 'react' ; import { Provider } from 'react-redux' ; import * as Redux from 'redux' ; import configureStore from 'redux-mock-store' ; import { loggedOutUser } from 'shared/auth/UserState' ; import { Connection , setMultiplayerConnection } from './multiplayer/Connection' ; import { createMiddleware } from './multiplayer/Middleware' ; import combinedReducers from './reducers/CombinedReducers' ; import { AppStateWithHistory } from './reducers/StateTypes' ; configure ( { adapter : new Adapter ( ) } ) ; export function newMockStoreWithInitializedState ( ) { return newMockStore ( combinedReducers ( { } as any , { type : '@@INIT' } ) ) ; } interface MockStore extends Redux . Store { clearActions : ( ) => void ; getActions : any ; } export function newMockStore ( state , client = new Connection ( ( ) => Promise . resolve ( false ) ) ) { const store = configureStore < AppStateWithHistory > ( [ createMiddleware ( client ) ] ) ( state as any as AppStateWithHistory ) ; ( store as any ) . multiplayerClient = client ; setMultiplayerConnection ( client ) ; return store ; } const defaultGlobalState = { settings : { numLocalPlayers : 1 } , } as any as AppStateWithHistory ; export function Reducer < A extends Redux . Action > ( reducer ) { const defaultInitialState = reducer ( undefined , ( { type : '@@INIT' } as any ) ) ; function internalReducerCommands ( initialState ) { const client = new Connection ( ) ; const store = configureStore < AppStateWithHistory > ( [ createMiddleware ( client ) ] ) ( defaultGlobalState ) ; return { execute : ( action ) => { store . dispatch ( action ) ; let newState = initialState ; for ( const a of store . getActions ( ) ) { newState = reducer ( newState , a ) ; } return newState ; } , expect : ( action ) => { store . dispatch ( action ) ; let newState = initialState ; for ( const a of store . getActions ( ) ) { newState = reducer ( newState , a ) ; } return { toChangeState : ( expectedChanges ) => { expect ( newState ) . toEqual ( jasmine . objectContaining ( expectedChanges ) ) ; } , toReturnState : ( expected ) => { expect ( newState ) . toEqual ( expected ) ; } , toStayTheSame : ( ) => { expect ( newState ) . toBe ( initialState ) ; } , } ; } , } ; } return { withState : ( state ) => { const initialState = state || defaultInitialState ; return internalReducerCommands ( initialState ) ; } , } ; } export function Action < A > ( action , baseState ? , client = new Connection ( ) ) { client . sendEvent = jasmine . createSpy ( 'sendEvent' ) ; setMultiplayerConnection ( client ) ; let store = configureStore < AppStateWithHistory > ( [ createMiddleware ( client ) ] ) ( ( baseState as any as AppStateWithHistory ) || defaultGlobalState ) ; function internalActionCommands ( ) { return { execute : ( ... a ) => { const v = store . dispatch ( action ( ... a ) ) ; if ( v && v instanceof Promise ) { return v . then ( ( ) => store . getActions ( ) ) ; } return store . getActions ( ) ; } , expect : ( ... a ) => { store . dispatch ( action ( ... a ) ) ; return { toDispatch ( expected ) { expect ( store . getActions ( ) ) . toContainEqual ( expected ) ; } , } ; } , } ; } return { withState ( storeState ) { store = configureStore < AppStateWithHistory > ( [ createMiddleware ( client ) ] ) ( storeState as AppStateWithHistory ) ; return internalActionCommands ( ) ; } , ... internalActionCommands ( ) , } ; } const BASE_ENZYME_STATE = { saved : { list : [ ] } , userQuests : { history : { } } , user : loggedOutUser , } ; export function render ( e , state ) { const store = newMockStore ( { ... BASE_ENZYME_STATE , ... state } ) ; const root = enzymeRender ( < Provider store = { store } > { e } < /Provider>, undefined / * renderOptions * /); return root ; } const unmounts = [ ] ; export function mountRoot ( e , state ) { const store = newMockStore ( { ... BASE_ENZYME_STATE , ... state } ) ; const root = enzymeMount ( < Provider store = { store } > { e } < /Provider>, undefined / * renderOptions * /); unmounts . push ( ( ) => root . unmount ( ) ) ; return root ; } export function mount ( e , state ) { return mountRoot ( e , state ) . childAt ( 0 ) ; } export function unmountAll ( ) { while ( unmounts . length > 0 ) { const um = unmounts . shift ( ) ; if ( ! um ) { return ; } um ( ) ; } }