prettier import { expect } from 'chai' ; import { mergeMap , map , delay , take } from 'rxjs/operators' ; import { asapScheduler , defer , Observable , from , of , timer } from 'rxjs' ; import { asInteropObservable } from '../helpers/interop-helper' ; import { TestScheduler } from 'rxjs/testing' ; import { observableMatcher } from '../helpers/observableMatcher' ; test describe ( 'mergeMap' , ( ) => { let testScheduler ; beforeEach ( ( ) => { testScheduler = new TestScheduler ( observableMatcher ) ; } ) ; it ( 'should map-and-flatten each item to an Observable' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const values = { x : 10 , y : 30 , z : 50 } ; const x = cold ( '    x-x-x|             ' , values ) ; const xsubs = [ '               --^----!             ' , '               --------^----!       ' , '               -----------^----!    ' , ] ; const e1 = hot ( '  --1-----3--5--------|' ) ; const e1subs = '  ^-------------------!' ; const expected = '--x-x-x-y-yzyz-z----|' ; const result = e1 . pipe ( mergeMap ( ( value ) => x . pipe ( map ( ( i ) => i * + value ) ) ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should support the deprecated resultSelector' , ( ) => { const results = [ ] ; of ( 1 , 2 , 3 ) . pipe ( mergeMap ( ( x ) => of ( x , x + 1 , x + 2 ) , ( a , b , i , ii ) => [ a , b , i , ii ] ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , error ( err ) { throw err ; } , complete ( ) { expect ( results ) . to . deep . equal ( [ [ 1 , 1 , 0 , 0 ] , [ 1 , 2 , 0 , 1 ] , [ 1 , 3 , 0 , 2 ] , [ 2 , 2 , 1 , 0 ] , [ 2 , 3 , 1 , 1 ] , [ 2 , 4 , 1 , 2 ] , [ 3 , 3 , 2 , 0 ] , [ 3 , 4 , 2 , 1 ] , [ 3 , 5 , 2 , 2 ] , ] ) ; } , } ) ; } ) ; it ( 'should support a void resultSelector (still deprecated)' , ( ) => { const results = [ ] ; of ( 1 , 2 , 3 ) . pipe ( mergeMap ( ( x ) => of ( x , x + 1 , x + 2 ) , void 0 ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , error ( err ) { throw err ; } , complete ( ) { expect ( results ) . to . deep . equal ( [ 1 , 2 , 3 , 2 , 3 , 4 , 3 , 4 , 5 ] ) ; } , } ) ; } ) ; it ( 'should support a void resultSelector (still deprecated) and concurrency limit' , ( ) => { const results = [ ] ; of ( 1 , 2 , 3 ) . pipe ( mergeMap ( ( x ) => of ( x , x + 1 , x + 2 ) , void 0 , 1 ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , error ( err ) { throw err ; } , complete ( ) { expect ( results ) . to . deep . equal ( [ 1 , 2 , 3 , 2 , 3 , 4 , 3 , 4 , 5 ] ) ; } , } ) ; } ) ; it ( 'should mergeMap many regular interval inners' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( '  ----a---a---a---(a|)                    ' ) ; const asubs = '   ^---------------!                       ' ; const b = cold ( '      ----b---b---(b|)                    ' ) ; const bsubs = '   ----^-----------!                       ' ; const c = cold ( '                  ----c---c---c---c---(c|)' ) ; const csubs = '   ----------------^-------------------!   ' ; const d = cold ( '                          ----(d|)        ' ) ; const dsubs = '   ------------------------^---!           ' ; const e1 = hot ( '  a---b-----------c-------d-------|       ' ) ; const e1subs = '  ^-------------------------------!       ' ; const expected = '----a---(ab)(ab)(ab)c---c---(cd)c---(c|)' ; const observableLookup = { a : a , b : b , c : c , d : d } ; const source = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( source ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should map values to constant resolved promises and merge' , ( done ) => { const source = from ( [ 4 , 3 , 2 , 1 ] ) ; const project = ( ) => from ( Promise . resolve ( 42 ) ) ; const results = [ ] ; source . pipe ( mergeMap ( project ) ) . subscribe ( { next : ( x ) => { results . push ( x ) ; } , error : ( err ) => { done ( new Error ( 'Subscriber error handler not supposed to be called.' ) ) ; } , complete : ( ) => { expect ( results ) . to . deep . equal ( [ 42 , 42 , 42 , 42 ] ) ; done ( ) ; } , } ) ; } ) ; it ( 'should map values to constant rejected promises and merge' , ( done ) => { const source = from ( [ 4 , 3 , 2 , 1 ] ) ; const project = ( ) => from ( Promise . reject < number > ( 42 ) ) ; source . pipe ( mergeMap ( project ) ) . subscribe ( { next : ( x ) => { done ( new Error ( 'Subscriber next handler not supposed to be called.' ) ) ; } , error : ( err ) => { expect ( err ) . to . equal ( 42 ) ; done ( ) ; } , complete : ( ) => { done ( new Error ( 'Subscriber complete handler not supposed to be called.' ) ) ; } , } ) ; } ) ; it ( 'should map values to resolved promises and merge' , ( done ) => { const source = from ( [ 4 , 3 , 2 , 1 ] ) ; const project = ( value , index ) => from ( Promise . resolve ( value + index ) ) ; const results = [ ] ; source . pipe ( mergeMap ( project ) ) . subscribe ( { next : ( x ) => { results . push ( x ) ; } , error : ( err ) => { done ( new Error ( 'Subscriber error handler not supposed to be called.' ) ) ; } , complete : ( ) => { expect ( results ) . to . deep . equal ( [ 4 , 4 , 4 , 4 ] ) ; done ( ) ; } , } ) ; } ) ; it ( 'should map values to rejected promises and merge' , ( done ) => { const source = from ( [ 4 , 3 , 2 , 1 ] ) ; const project = ( value , index ) => from ( Promise . reject < string > ( '' + value + '-' + index ) ) ; source . pipe ( mergeMap ( project ) ) . subscribe ( { next : ( x ) => { done ( new Error ( 'Subscriber next handler not supposed to be called.' ) ) ; } , error : ( err ) => { expect ( err ) . to . equal ( '4-0' ) ; done ( ) ; } , complete : ( ) => { done ( new Error ( 'Subscriber complete handler not supposed to be called.' ) ) ; } , } ) ; } ) ; it ( 'should mergeMap many outer values to many inner values' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                        ' ) ; const xsubs = [ '               -^-------------------!                        ' , '               ---------^-------------------!                ' , '               -----------------^-------------------!        ' , '               -------------------------^-------------------!' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------|            ' ) ; const e1subs = '  ^--------------------------------!            ' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l---|' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, complete late' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                            ' ) ; const xsubs = [ '               -^-------------------!                            ' , '               ---------^-------------------!                    ' , '               -----------------^-------------------!            ' , '               -------------------------^-------------------!    ' , ] ; const e1 = hot ( '  -a-------b-------c-------d-----------------------|' ) ; const e1subs = '  ^------------------------------------------------!' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-------|' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, outer never completes' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                                  ' ) ; const xsubs = [ '               -^-------------------!                                  ' , '               ---------^-------------------!                          ' , '               -----------------^-------------------!                  ' , '               -------------------------^-------------------!          ' , '               ---------------------------------^-------------------!  ' , '               -------------------------------------------------^-----!' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------e---------------f------' ) ; const e1subs = '  ^------------------------------------------------------!' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--' ; const unsub = '   -------------------------------------------------------!' ; const source = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( source , unsub ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not break unsubscription chains when result is unsubscribed explicitly' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                                  ' ) ; const xsubs = [ '               -^-------------------!                                  ' , '               ---------^-------------------!                          ' , '               -----------------^-------------------!                  ' , '               -------------------------^-------------------!          ' , '               ---------------------------------^-------------------!  ' , '               -------------------------------------------------^-----!' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------e---------------f------' ) ; const e1subs = '  ^------------------------------------------------------!' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--' ; const unsub = '   -------------------------------------------------------!' ; const source = e1 . pipe ( map ( ( x ) => x ) , mergeMap ( ( ) => x ) , map ( ( x ) => x ) ) ; expectObservable ( source , unsub ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not break unsubscription chains with interop inners when result is unsubscribed explicitly' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '           --a--b--c--d--e--|           ' ) ; const xsubs = '   ---------^-----------!                ' ; const y = cold ( '                     ---f---g---h---i--|' ) ; const ysubs = '   -------------------^-!                ' ; const e1 = hot ( '  ---------x---------y---------|        ' ) ; const e1subs = '  ^--------------------!                ' ; const expected = '-----------a--b--c--d-                ' ; const unsub = '   ---------------------!                ' ; const observableLookup = { x : x , y : y } ; const result = e1 . pipe ( mergeMap ( ( x ) => of ( x ) ) , mergeMap ( ( value ) => asInteropObservable ( observableLookup [ value ] ) ) , mergeMap ( ( x ) => of ( x ) ) ) ; expectObservable ( result , unsub ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( y . subscriptions ) . toBe ( ysubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, inner never completes' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l-------------------------' ) ; const xsubs = [ '               -^-----------------------------------------' , '               ---------^---------------------------------' , '               -----------------^-------------------------' , '               -------------------------^-----------------' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------|         ' ) ; const e1subs = '  ^--------------------------------!         ' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, and inner throws' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l-------#   ' ) ; const xsubs = [ '               -^-----------------------!   ' , '               ---------^---------------!   ' , '               -----------------^-------!   ' , '               -------------------------(^!)' , ] ; const e1 = hot ( '  -a-------b-------c-------d   ' ) ; const e1subs = '  ^------------------------!   ' ; const expected = '-----i---j---(ki)(lj)(ki)#   ' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, and outer throws' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|            ' ) ; const xsubs = [ '               -^-------------------!            ' , '               ---------^-------------------!    ' , '               -----------------^---------------!' , '               -------------------------^-------!' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------#' ) ; const e1subs = '  ^--------------------------------!' ; const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)#' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to many inner, both inner and outer throw' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---#            ' ) ; const xsubs = [ '               -^-------------------!            ' , '               ---------^-----------!            ' , '               -----------------^---!            ' , ] ; const e1 = hot ( '  -a-------b-------c-------d-------#' ) ; const e1subs = '  ^--------------------!            ' ; const expected = '-----i---j---(ki)(lj)#            ' ; const result = e1 . pipe ( mergeMap ( ( ) => x ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap to many cold Observable, with parameter concurrency=1' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                                        ' ) ; const xsubs = [ '               -^-------------------!                                        ' , '               ---------------------^-------------------!                    ' , '               -----------------------------------------^-------------------!' , ] ; const e1 = hot ( '  -a-------b-------c---|                                        ' ) ; const e1subs = '  ^--------------------!                                        ' ; const expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|' ; const project = ( ) => x ; const result = e1 . pipe ( mergeMap ( project , 1 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap to many cold Observable, with parameter concurrency=2' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const x = cold ( '   ----i---j---k---l---|                    ' ) ; const xsubs = [ '               -^-------------------!                    ' , '               ---------^-------------------!            ' , '               ---------------------^-------------------!' , ] ; const e1 = hot ( '  -a-------b-------c---|                    ' ) ; const e1subs = '  ^--------------------!                    ' ; const expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|' ; const project = ( ) => x ; const result = e1 . pipe ( mergeMap ( project , 2 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap to many hot Observable, with parameter concurrency=1' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const a = hot ( '   x----i---j---k---l---|                                        ' ) ; const asubs = '   -^-------------------!                                        ' ; const b = hot ( '   -x-x-xxxx-x-x-xxxxx-x----i---j---k---l---|                    ' ) ; const bsubs = '   ---------------------^-------------------!                    ' ; const c = hot ( '   x-xxxx---x-x-x-x-x-xx--x--x-x--x--xxxx-x-----i---j---k---l---|' ) ; const csubs = '   -----------------------------------------^-------------------!' ; const e1 = hot ( '  -a-------b-------c---|                                        ' ) ; const e1subs = '  ^--------------------!                                        ' ; const expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|' ; const inners = { a : a , b : b , c : c } ; const project = ( x ) => inners [ x ] ; const result = e1 . pipe ( mergeMap ( project , 1 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap to many hot Observable, with parameter concurrency=2' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const x = hot ( '   x----i---j---k---l---|                    ' ) ; const xsubs = '   -^-------------------!                    ' ; const y = hot ( '   -x-x-xxxx----i---j---k---l---|            ' ) ; const ysubs = '   ---------^-------------------!            ' ; const z = hot ( '   x-xxxx---x-x-x-x-x-xx----i---j---k---l---|' ) ; const zsubs = '   ---------------------^-------------------!' ; const e1 = hot ( '  -a-------b-------c---|                    ' ) ; const e1subs = '  ^--------------------!                    ' ; const expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|' ; const inners = { a : x , b : y , c : z } ; const project = ( x ) => inners [ x ] ; const result = e1 . pipe ( mergeMap ( project , 2 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( x . subscriptions ) . toBe ( xsubs ) ; expectSubscriptions ( y . subscriptions ) . toBe ( ysubs ) ; expectSubscriptions ( z . subscriptions ) . toBe ( zsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, where all inners are finite' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^------------------------------!             ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^--------------!                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^------------------------------!' ; const f = cold ( '                                      --|            ' ) ; const fsubs = '       --------------------------------^-!            ' ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = '       --------------------------------------^-----!  ' ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g|       ' ) ; const e1subs = '      ^--------------------------------------!       ' ; const expected = '    ---2--3--4--5---1--2--3--2--3--6--4--5---1-2--|' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const result = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, all inners finite except one' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^------------------------------!             ' ; const d = cold ( '              -----------2--3-                       ' ) ; const dsubs = '       --------^---------------                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^------------------------------!' ; const f = cold ( '                                      --|            ' ) ; const fsubs = '       --------------------------------^-!            ' ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = '       --------------------------------------^-----!  ' ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g|       ' ) ; const e1subs = '      ^--------------------------------------!       ' ; const expected = '    ---2--3--4--5---1--2--3--2--3--6--4--5---1-2---' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const result = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, inners finite, outer does not complete' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^------------------------------!             ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^--------------!                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^------------------------------!' ; const f = cold ( '                                      --|            ' ) ; const fsubs = '       --------------------------------^-!            ' ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = '       --------------------------------------^-----!  ' ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g--------' ) ; const e1subs = '      ^----------------------------------------------' ; const expected = '    ---2--3--4--5---1--2--3--2--3--6--4--5---1-2---' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const result = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, all inners finite, and outer throws' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^------------------------------!             ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^--------------!                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^-----------------------!       ' ; const f = cold ( '                                      --|            ' ) ; const fsubs = '       --------------------------------^-!            ' ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = '       --------------------------------------^!       ' ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g#       ' ) ; const e1subs = '      ^--------------------------------------!       ' ; const expected = '    ---2--3--4--5---1--2--3--2--3--6--4--5-#       ' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const result = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, all inners complete except one throws' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-#             ' ) ; const csubs = '       --^------------------------------!             ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^--------------!                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^-----------------!             ' ; const f = cold ( '                                      --|            ' ) ; const fsubs = '       --------------------------------^!             ' ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = [ ] ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g|       ' ) ; const e1subs = '      ^--------------------------------!             ' ; const expected = '    ---2--3--4--5---1--2--3--2--3--6-#             ' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const result = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, all inners finite, outer is unsubscribed' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^---------------------------!                ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^--------------!                       ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = '       ---------------^--------------!                ' ; const f = cold ( '                                      --|            ' ) ; const fsubs = [ ] ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = [ ] ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g|' ) ; const e1subs = '      ^-----------------------------!                ' ; const expected = '    ---2--3--4--5---1--2--3--2--3--                ' ; const unsub = '       ------------------------------!                ' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const source = e1 . pipe ( mergeMap ( ( value ) => observableLookup [ value ] ) ) ; expectObservable ( source , unsub ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many complex, all inners finite, project throws' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const a = cold ( ' -#                                                  ' ) ; const asubs = [ ] ; const b = cold ( '   -#                                                ' ) ; const bsubs = [ ] ; const c = cold ( '        -2--3--4--5------------------6-|             ' ) ; const csubs = '       --^------------!                               ' ; const d = cold ( '              -----------2--3|                       ' ) ; const dsubs = '       --------^------!                               ' ; const e = cold ( '                     -1--------2--3-----4--5--------|' ) ; const esubs = [ ] ; const f = cold ( '                                      --|            ' ) ; const fsubs = [ ] ; const g = cold ( '                                            ---1-2|  ' ) ; const gsubs = [ ] ; const e1 = hot ( '-a-b--^-c-----d------e----------------f-----g|       ' ) ; const e1subs = '      ^--------------!                               ' ; const expected = '    ---2--3--4--5--#                               ' ; const observableLookup = { a : a , b : b , c : c , d : d , e : e , f : f , g : g } ; const source = e1 . pipe ( mergeMap ( ( value ) => { if ( value === 'e' ) { throw 'error' ; } return observableLookup [ value ] ; } ) ) ; expectObservable ( source ) . toBe ( expected ) ; expectSubscriptions ( a . subscriptions ) . toBe ( asubs ) ; expectSubscriptions ( b . subscriptions ) . toBe ( bsubs ) ; expectSubscriptions ( c . subscriptions ) . toBe ( csubs ) ; expectSubscriptions ( d . subscriptions ) . toBe ( dsubs ) ; expectSubscriptions ( e . subscriptions ) . toBe ( esubs ) ; expectSubscriptions ( f . subscriptions ) . toBe ( fsubs ) ; expectSubscriptions ( g . subscriptions ) . toBe ( gsubs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; function arrayRepeat < T > ( value , times ) { const results = [ ] ; for ( let i = 0 ; i < times ; i ++ ) { results . push ( value ) ; } return results ; } it ( 'should mergeMap many outer to an array for each value' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  2-----4--------3--------2-------|' ) ; const e1subs = '  ^-------------------------------!' ; const expected = '(22)--(4444)---(333)----(22)----|' ; const source = e1 . pipe ( mergeMap ( ( value ) => arrayRepeat ( value , + value ) ) ) ; expectObservable ( source ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to inner arrays, and outer throws' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  2-----4--------3--------2-------#' ) ; const e1subs = '  ^-------------------------------!' ; const expected = '(22)--(4444)---(333)----(22)----#' ; const source = e1 . pipe ( mergeMap ( ( value ) => arrayRepeat ( value , + value ) ) ) ; expectObservable ( source ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to inner arrays, outer gets unsubscribed' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  2-----4--------3--------2-------|' ) ; const e1subs = '  ^------------!                   ' ; const expected = '(22)--(4444)--                   ' ; const unsub = '   -------------!                   ' ; const source = e1 . pipe ( mergeMap ( ( value ) => arrayRepeat ( value , + value ) ) ) ; expectObservable ( source , unsub ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mergeMap many outer to inner arrays, project throws' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  2-----4--------3--------2-------|' ) ; const e1subs = '  ^--------------!                 ' ; const expected = '(22)--(4444)---#                 ' ; const source = e1 . pipe ( mergeMap ( ( value ) => { if ( value === '3' ) { throw 'error' ; } return arrayRepeat ( value , + value ) ; } ) ) ; expectObservable ( source ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should map and flatten' , ( ) => { const source = of ( 1 , 2 , 3 , 4 ) . pipe ( mergeMap ( ( x ) => of ( x + '!' ) ) ) ; const expected = [ '1!' , '2!' , '3!' , '4!' ] ; let completed = false ; source . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , complete : ( ) => { expect ( expected . length ) . to . equal ( 0 ) ; completed = true ; } , } ) ; expect ( completed ) . to . be . true ; } ) ; it ( 'should map and flatten an Array' , ( ) => { const source = of ( 1 , 2 , 3 , 4 ) . pipe ( mergeMap ( ( x ) : any => [ x + '!' ] ) ) ; const expected = [ '1!' , '2!' , '3!' , '4!' ] ; let completed = false ; source . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , complete : ( ) => { expect ( expected . length ) . to . equal ( 0 ) ; completed = true ; } , } ) ; expect ( completed ) . to . be . true ; } ) ; it ( 'should support nested merges' , ( done ) => { const results = [ ] ; of ( 1 ) . pipe ( mergeMap ( ( ) => defer ( ( ) => of ( 2 , asapScheduler ) ) . pipe ( mergeMap ( ( ) => defer ( ( ) => of ( 3 , asapScheduler ) ) ) ) ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , complete ( ) { results . push ( 'done' ) ; } , } ) ; setTimeout ( ( ) => { expect ( results ) . to . deep . equal ( [ 3 , 'done' ] ) ; done ( ) ; } , 0 ) ; } ) ; it ( 'should support nested merges with promises' , ( done ) => { const results = [ ] ; of ( 1 ) . pipe ( mergeMap ( ( ) => from ( Promise . resolve ( 2 ) ) . pipe ( mergeMap ( ( ) => Promise . resolve ( 3 ) ) ) ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , complete ( ) { results . push ( 'done' ) ; } , } ) ; setTimeout ( ( ) => { expect ( results ) . to . deep . equal ( [ 3 , 'done' ] ) ; done ( ) ; } , 0 ) ; } ) ; it ( 'should support wrapped sources' , ( done ) => { const results = [ ] ; const wrapped = new Observable < number > ( ( subscriber ) => { const subscription = timer ( 0 , asapScheduler ) . subscribe ( subscriber ) ; return ( ) => subscription . unsubscribe ( ) ; } ) ; wrapped . pipe ( mergeMap ( ( ) => timer ( 0 , asapScheduler ) ) ) . subscribe ( { next ( value ) { results . push ( value ) ; } , complete ( ) { results . push ( 'done' ) ; } , } ) ; setTimeout ( ( ) => { expect ( results ) . to . deep . equal ( [ 0 , 'done' ] ) ; done ( ) ; } , 0 ) ; } ) ; it ( 'should properly handle errors from iterables that are processed after some async' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const noXError = new Error ( 'we do not allow x' ) ; const e1 = cold ( ' -----a------------b-----|' , { a : [ 'o' , 'o' , 'o' ] , b : [ 'o' , 'x' , 'o' ] } ) ; const e1subs = '  ^-----------------!      ' ; const expected = '-----(ooo)--------(o#)   ' ; const iterable = function * ( data ) { for ( const d of data ) { if ( d === 'x' ) { throw noXError ; } yield d ; } } ; const result = e1 . pipe ( mergeMap ( ( x ) => of ( x ) . pipe ( delay ( 0 ) , mergeMap ( iterable ) ) ) ) ; expectObservable ( result ) . toBe ( expected , undefined , noXError ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should stop listening to a synchronous observable when unsubscribed' , ( ) => { const sideEffects = [ ] ; const synchronousObservable = new Observable < number > ( ( subscriber ) => { for ( let i = 0 ; ! subscriber . closed && i < 10 ; i ++ ) { sideEffects . push ( i ) ; subscriber . next ( i ) ; } } ) ; synchronousObservable . pipe ( mergeMap ( ( value ) => of ( value ) ) , take ( 3 ) ) . subscribe ( ( ) => { } ) ; expect ( sideEffects ) . to . deep . equal ( [ 0 , 1 , 2 ] ) ; } ) ; } ) ;