import { applyMiddleware , createStore } from 'redux' ; import { createMetaReducer , createMiddleware } from '../' ; function runIntegrationTests ( title , prepareStore ) { describe ( title , ( ) => { describe ( 'When an action with an associated event definition is dispatched' , ( ) => { it ( 'creates the event and pushes it to the target' , ( ) => { const eventsMap = { ROUTE_CHANGED : ( action , prevState , nextState ) => ( { hitType : 'pageview' , page : action . payload , referrer : prevState . route , numActions : nextState . numActions , } ) , } ; const target = jest . fn ( ) ; const initialState = { route : '/home' , numActions : 0 , } ; const reducer = ( state = initialState , action ) => { if ( action . type === 'ROUTE_CHANGED' ) { return Object . assign ( { } , state , { route : action . payload , numActions : state . numActions + 1 , } ) ; } return state ; } ; const store = prepareStore ( reducer , eventsMap , target ) ; store . dispatch ( { type : 'ROUTE_CHANGED' , payload : '/my-account' } ) ; expect ( target ) . toHaveBeenCalledWith ( [ { hitType : 'pageview' , page : '/my-account' , referrer : '/home' , numActions : 1 , } , ] ) ; } ) ; } ) ; describe ( 'When an action does not have an associated event definition' , ( ) => { it ( 'does not push any events to the target' , ( ) => { const eventsMap = { } ; const target = jest . fn ( ) ; const reducer = state => state ; const store = prepareStore ( reducer , eventsMap , target ) ; store . dispatch ( { type : 'SOME_REDUX_ACTION' } ) ; expect ( target ) . not . toHaveBeenCalled ( ) ; } ) ; } ) ; describe ( 'When an event definition is validated' , ( ) => { it ( 'only pushes valid events to the target' , ( ) => { const onlyEventsOfType = ( ... hitTypes ) => eventDef => ( ... args ) => eventDef ( ... args ) . map ( event => ( [ ... hitTypes ] . includes ( event . hitType ) ? event : null ) ) ; const eventDef = ( ) => [ { hitType : 'pageview' } , { hitType : 'not-pageview-or-error' } , ] ; const eventsMap = { ROUTE_CHANGED : onlyEventsOfType ( 'pageview' , 'error' ) ( eventDef ) , } ; const target = jest . fn ( ) ; const reducer = ( state = { route : '/home' } ) => state ; const store = prepareStore ( reducer , eventsMap , target ) ; store . dispatch ( { type : 'ROUTE_CHANGED' , payload : '/my-account' } ) ; expect ( target ) . toHaveBeenCalledWith ( [ { hitType : 'pageview' } ] ) ; } ) ; } ) ; describe ( 'When given an eventsMapper instead of an eventsMap' , ( ) => { it ( 'correctly maps dispatched actions to event definitions' , ( ) => { const eventsMapper = action => { switch ( action . type ) { case 'ACTION_A' : return [ ( ) => ( { event : 'ACTION_A_EVENT_1' } ) , ( ) => ( { event : 'ACTION_A_EVENT_2' } ) , ] ; case 'ACTION_C' : return ( ) => ( { event : 'ACTION_C_EVENT' } ) ; default : return [ ] ; } } ; const target = jest . fn ( ) ; const reducer = state => state ; const store = prepareStore ( reducer , eventsMapper , target ) ; store . dispatch ( { type : 'ACTION_A' } ) ; store . dispatch ( { type : 'ACTION_B' } ) ; store . dispatch ( { type : 'ACTION_C' } ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'ACTION_A_EVENT_1' } , { event : 'ACTION_A_EVENT_2' } , ] ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'ACTION_C_EVENT' } ] ) ; } ) ; } ) ; } ) ; } runIntegrationTests ( 'createMiddleware(eventsMap | eventsMapper, target, extensions?)' , ( reducer , eventsMapOrMapper , target ) => createStore ( reducer , applyMiddleware ( createMiddleware ( eventsMapOrMapper , target ) ) ) ) ; runIntegrationTests ( 'createMetaReducer(eventsMap | eventsMapper, target, extensions?)' , ( reducer , eventsMap , target ) => createStore ( createMetaReducer ( eventsMap , target ) ( reducer ) ) ) ;