import registerEvents from '../register-events' ; describe ( 'When given an array of events, and a target' , ( ) => { it ( 'pushes events to the target' , ( ) => { const events = [ { event : 'some-event' } ] ; const target = jest . fn ( ) ; registerEvents ( events , target ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'some-event' } ] ) ; } ) ; } ) ; describe ( 'When given a logger extension' , ( ) => { it ( 'logs the events' , ( ) => { const events = [ { event : 'some-event' } ] ; const target = jest . fn ( ) ; const action = { type : 'SOME_ACTION_TYPE' } ; const prevState = { route : '/home' } ; const extensions = { logger : jest . fn ( ) , } ; registerEvents ( events , target , extensions , prevState , action ) ; expect ( extensions . logger ) . toHaveBeenCalledWith ( events , action , prevState ) ; } ) ; } ) ; describe ( 'When given an offline storage extension' , ( ) => { describe ( 'If the app is offline' , ( ) => { const events = [ { event : 'some-event' } ] ; const target = jest . fn ( ) ; const prevState = { isConnected : true } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : false } ; const extensions = { logger : jest . fn ( ) , offlineStorage : { saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; registerEvents ( events , target , extensions , prevState , action , nextState ) ; it ( 'calls offlineStorage.saveEvents with the events' , ( ) => { expect ( extensions . offlineStorage . saveEvents ) . toHaveBeenCalledWith ( events ) ; } ) ; it ( 'does not push events to the target' , ( ) => { expect ( target ) . not . toHaveBeenCalled ( ) ; } ) ; it ( 'logs events correctly' , ( ) => { expect ( extensions . logger ) . toHaveBeenCalledWith ( events , action , prevState , true , false ) ; } ) ; } ) ; describe ( 'If the app is offline and there is no events' , ( ) => { it ( 'does not throw an error' , ( ) => { const events = [ ] ; const target = jest . fn ( ) ; const prevState = { isConnected : true } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : false } ; const extensions = { logger : jest . fn ( ) , offlineStorage : { saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; expect ( ( ) => { registerEvents ( events , target , extensions , prevState , action , nextState ) ; } ) . not . toThrow ( ) ; } ) ; } ) ; describe ( 'If the app is online (with events)' , ( ) => { const events = [ { event : 'some-event' } ] ; const target = jest . fn ( ) ; const prevState = { isConnected : false } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : true } ; const oldEvents = [ { event : 'some-old-event' } ] ; const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; registerEvents ( events , target , extensions , prevState , action , nextState ) ; it ( 'pushes the new events to the target' , ( ) => { expect ( target ) . toHaveBeenCalledWith ( events ) ; } ) ; it ( 'logs events correctly' , ( ) => { expect ( extensions . logger ) . toHaveBeenCalledWith ( events , action , prevState ) ; } ) ; it ( 'calls offlineStorage.purgeEvents' , ( ) => { expect ( extensions . offlineStorage . purgeEvents ) . toHaveBeenCalled ( ) ; } ) ; it ( 'pushes the purged events to the target' , ( ) => { expect ( target ) . toHaveBeenCalledWith ( oldEvents ) ; } ) ; it ( 'logs the purged events' , ( ) => { expect ( extensions . logger ) . toHaveBeenCalledWith ( oldEvents , null , null , false , true ) ; } ) ; } ) ; describe ( 'If the app is online (without events)' , ( ) => { const events = [ ] ; const target = jest . fn ( ) ; const prevState = { isConnected : false } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : true } ; const oldEvents = [ { event : 'some-old-event' } ] ; const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; registerEvents ( events , target , extensions , prevState , action , nextState ) ; it ( 'does not push any events to the target' , ( ) => { expect ( target ) . not . toHaveBeenCalledWith ( [ ] ) ; } ) ; it ( 'logs events correctly' , ( ) => { expect ( extensions . logger ) . toHaveBeenCalledWith ( [ ] , action , prevState ) ; } ) ; it ( 'pushes the purged events to the target' , ( ) => { expect ( target ) . toHaveBeenCalledWith ( oldEvents ) ; } ) ; it ( 'logs the purged events' , ( ) => { expect ( extensions . logger ) . toHaveBeenCalledWith ( oldEvents , null , null , false , true ) ; } ) ; } ) ; } ) ; describe ( 'Asynchronous events' , ( ) => { describe ( 'When given an array with an async event that returns one event' , ( ) => { it ( 'pushes the event to the target once available' , async ( ) => { const events = [ Promise . resolve ( { event : 'some event' } ) ] ; const target = jest . fn ( ) ; await registerEvents ( events , target ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'some event' } ] ) ; } ) ; } ) ; describe ( 'When given an array with an async event that returns multiple events' , ( ) => { it ( 'pushes the events to the target once available' , async ( ) => { const events = [ Promise . resolve ( [ { event : 'some event' } , { event : 'some other event' } , ] ) , ] ; const target = jest . fn ( ) ; await registerEvents ( events , target ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'some event' } , { event : 'some other event' } , ] ) ; } ) ; } ) ; describe ( 'When given an array with some async events and some sync events' , ( ) => { const events = [ { event : 'sync-event-1' } , Promise . resolve ( { event : 'async-event-1' } ) , { event : 'sync-event-2' } , Promise . resolve ( [ { event : 'async-event-2' } , { event : 'async-event-3' } ] ) , ] ; it ( 'pushes the sync events immediately to the target' , ( ) => { const target = jest . fn ( ) ; registerEvents ( events , target ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'sync-event-1' } , { event : 'sync-event-2' } , ] ) ; } ) ; it ( 'pushes the async events to the target once they are available' , async ( ) => { const target = jest . fn ( ) ; await registerEvents ( events , target ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'async-event-1' } , { event : 'async-event-2' } , { event : 'async-event-3' } , ] ) ; } ) ; } ) ; describe ( 'When given a logger extension' , ( ) => { describe ( 'and an array with an async event that returns one event' , ( ) => { it ( 'logs the event once available' , async ( ) => { const events = [ Promise . resolve ( { event : 'some event' } ) ] ; const target = jest . fn ( ) ; const action = { type : 'SOME_ACTION_TYPE' } ; const prevState = { route : '/home' } ; const extensions = { logger : jest . fn ( ) , } ; await registerEvents ( events , target , extensions , prevState , action ) ; expect ( extensions . logger ) . toHaveBeenCalledWith ( [ { event : 'some event' } ] , action , prevState ) ; } ) ; } ) ; describe ( 'and an array with an async event that returns multiple events' , ( ) => { it ( 'log the events once available' , async ( ) => { const events = [ Promise . resolve ( [ { event : 'some event' } , { event : 'some other event' } , ] ) , ] ; const target = jest . fn ( ) ; const action = { type : 'SOME_ACTION_TYPE' } ; const prevState = { route : '/home' } ; const extensions = { logger : jest . fn ( ) , } ; await registerEvents ( events , target , extensions , prevState , action ) ; expect ( extensions . logger ) . toHaveBeenCalledWith ( [ { event : 'some event' } , { event : 'some other event' } ] , action , prevState ) ; } ) ; } ) ; describe ( 'and an array with some async events and some sync events' , ( ) => { const events = [ { event : 'sync-event-1' } , Promise . resolve ( { event : 'async-event-1' } ) , { event : 'sync-event-2' } , Promise . resolve ( [ { event : 'async-event-2' } , { event : 'async-event-3' } , ] ) , ] ; it ( 'logs the sync event immediately' , ( ) => { const target = jest . fn ( ) ; const action = { type : 'SOME_ACTION_TYPE' } ; const prevState = { route : '/home' } ; const extensions = { logger : jest . fn ( ) , } ; registerEvents ( events , target , extensions , prevState , action ) ; expect ( extensions . logger ) . toHaveBeenCalledWith ( [ { event : 'sync-event-1' } , { event : 'sync-event-2' } ] , action , prevState ) ; } ) ; it ( 'logs the async events once they are available' , async ( ) => { const target = jest . fn ( ) ; const action = { type : 'SOME_ACTION_TYPE' } ; const prevState = { route : '/home' } ; const extensions = { logger : jest . fn ( ) , } ; await registerEvents ( events , target , extensions , prevState , action ) ; expect ( extensions . logger ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; } ) ; } ) ; describe ( 'When given an offline storage extension' , ( ) => { describe ( 'If the app is offline' , ( ) => { const events = [ { event : 'sync-event-1' } , Promise . resolve ( { event : 'async-event-1' } ) , { event : 'sync-event-2' } , Promise . resolve ( [ { event : 'async-event-2' } , { event : 'async-event-3' } , ] ) , ] ; const target = jest . fn ( ) ; const prevState = { isConnected : true } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : false } ; const oldEvents = [ { event : 'some-old-event' } ] ; it ( 'saves sync events immediately and async events once available' , async ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; await registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( extensions . offlineStorage . saveEvents . mock . calls ) . toEqual ( [ [ [ { event : 'sync-event-1' } , { event : 'sync-event-2' } ] ] , [ [ { event : 'async-event-1' } , { event : 'async-event-2' } , { event : 'async-event-3' } , ] , ] , ] ) ; } ) ; it ( 'does not push any events to the target' , async ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; await registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( target ) . not . toHaveBeenCalled ( ) ; } ) ; it ( 'logs events correctly' , async ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; await registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( extensions . logger . mock . calls ) . toEqual ( [ [ [ { event : 'sync-event-1' } , { event : 'sync-event-2' } ] , action , prevState , true , false , ] , [ [ { event : 'async-event-1' } , { event : 'async-event-2' } , { event : 'async-event-3' } , ] , action , prevState , true , false , ] , ] ) ; } ) ; } ) ; describe ( 'if the app is online' , ( ) => { const events = [ { event : 'sync-event-1' } , Promise . resolve ( { event : 'async-event-1' } ) , { event : 'sync-event-2' } , Promise . resolve ( [ { event : 'async-event-2' } , { event : 'async-event-3' } , ] ) , ] ; const target = jest . fn ( ) ; const prevState = { isConnected : false } ; const action = { type : 'SOME_ACTION_TYPE' } ; const nextState = { isConnected : true } ; const oldEvents = [ { event : 'some-old-event' } ] ; it ( 'pushes new sync events to the target synchronously' , ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'sync-event-1' } , { event : 'sync-event-2' } , ] ) ; } ) ; it ( 'pushes new async event to the target once they are ready' , async ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; await registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'async-event-1' } , { event : 'async-event-2' } , { event : 'async-event-3' } , ] ) ; } ) ; it ( 'pushes purged events to the target' , ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( target ) . toHaveBeenCalledWith ( [ { event : 'some-old-event' } ] ) ; } ) ; it ( 'logs events correctly' , async ( ) => { const extensions = { logger : jest . fn ( ) , offlineStorage : { purgeEvents : jest . fn ( ) . mockImplementationOnce ( cb => cb ( oldEvents ) ) , saveEvents : jest . fn ( ) , isConnected : state => state . isConnected , } , } ; await registerEvents ( events , target , extensions , prevState , action , nextState ) ; expect ( extensions . logger . mock . calls ) . toEqual ( [ [ [ { event : 'sync-event-1' } , { event : 'sync-event-2' } ] , action , prevState , ] , [ [ { event : 'some-old-event' } ] , null , null , false , true ] , [ [ { event : 'async-event-1' } , { event : 'async-event-2' } , { event : 'async-event-3' } , ] , action , prevState , ] , ] ) ; } ) ; } ) ; } ) ; } ) ;