prettier import { expect } from 'chai' ; import { multicast , tap , mergeMapTo , takeLast , mergeMap , refCount , retry , repeat , switchMap , map , take } from 'rxjs/operators' ; import { Subject , ReplaySubject , of , ConnectableObservable , zip , concat , Subscription , Observable , from } from 'rxjs' ; import { TestScheduler } from 'rxjs/testing' ; import { observableMatcher } from '../helpers/observableMatcher' ; test describe ( 'multicast' , ( ) => { let testScheduler ; beforeEach ( ( ) => { testScheduler = new TestScheduler ( observableMatcher ) ; } ) ; it ( 'should mirror a simple source Observable' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --1-2---3-4--5-|' ) ; const e1subs = '  ^--------------!' ; const expected = '--1-2---3-4--5-|' ; const result = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; result . connect ( ) ; } ) ; } ) ; it ( 'should accept Subjects' , ( done ) => { const expected = [ 1 , 2 , 3 , 4 ] ; const connectable = of ( 1 , 2 , 3 , 4 ) . pipe ( multicast ( new Subject < number > ( ) ) ) as ConnectableObservable < number > ; connectable . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { done ( ) ; } , } ) ; connectable . connect ( ) ; } ) ; it ( 'should multicast a ConnectableObservable' , ( done ) => { const expected = [ 1 , 2 , 3 , 4 ] ; const source = new Subject < number > ( ) ; const connectable = source . pipe ( multicast ( new Subject < number > ( ) ) ) as ConnectableObservable < number > ; const replayed = connectable . pipe ( multicast ( new ReplaySubject < number > ( ) ) ) as ConnectableObservable < number > ; connectable . connect ( ) ; replayed . connect ( ) ; source . next ( 1 ) ; source . next ( 2 ) ; source . next ( 3 ) ; source . next ( 4 ) ; source . complete ( ) ; replayed . pipe ( tap ( { next ( x ) { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , complete ( ) { expect ( expected . length ) . to . equal ( 0 ) ; } , } ) ) . subscribe ( { error : done , complete : done } ) ; } ) ; it ( 'should accept Subject factory functions' , ( done ) => { const expected = [ 1 , 2 , 3 , 4 ] ; const connectable = of ( 1 , 2 , 3 , 4 ) . pipe ( multicast ( ( ) => new Subject < number > ( ) ) ) as ConnectableObservable < number > ; connectable . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { done ( ) ; } , } ) ; connectable . connect ( ) ; } ) ; it ( 'should accept a multicast selector and connect to a hot source for each subscriber' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const selector = ( x ) => zip ( x , x ) . pipe ( map ( ( [ a , b ] ) => ( parseInt ( a ) + parseInt ( b ) ) . toString ( ) ) ) ; const e1 = hot ( '         -1-2-3----4-|' ) ; const e1subs = [ '                      ^-----------!' , '                      ----^-------!' , '                      --------^---!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory , selector ) ) ; const subscriber1 = hot ( 'a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -2-4-6----8-|' ; const subscriber2 = hot ( '----b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----6----8-|' ; const subscriber3 = hot ( '--------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ----------8-|' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should accept a multicast selector and connect to a cold source for each subscriber' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const selector = ( x ) => zip ( x , x ) . pipe ( map ( ( [ a , b ] ) => ( parseInt ( a ) + parseInt ( b ) ) . toString ( ) ) ) ; const e1 = cold ( '        -1-2-3----4-|        ' ) ; const e1subs = [ '                      ^-----------!        ' , '                      ----^-----------!    ' , '                      --------^-----------!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory , selector ) ) ; const subscriber1 = hot ( 'a|                   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -2-4-6----8-|        ' ; const subscriber2 = hot ( '----b|               ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----2-4-6----8-|    ' ; const subscriber3 = hot ( '--------c|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ---------2-4-6----8-|' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( "should accept a multicast selector and respect the subject's messaging semantics" , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new ReplaySubject < string > ( 1 ) ; const selector = ( x ) => concat ( x , x . pipe ( takeLast ( 1 ) ) ) ; const e1 = cold ( '        -1-2-3----4-|           ' ) ; const e1subs = [ '                      ^-----------!           ' , '                      ----^-----------!       ' , '                      --------^-----------!   ' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory , selector ) ) ; const subscriber1 = hot ( 'a|                      ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -1-2-3----4-(4|)        ' ; const subscriber2 = hot ( '----b|                  ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----1-2-3----4-(4|)    ' ; const subscriber3 = hot ( '--------c|              ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ---------1-2-3----4-(4|)' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should do nothing if connect is not called, despite subscriptions' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --1-2---3-4--5-|' ) ; const e1subs = [ ] ; const expected = '----------------' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) ; expectObservable ( multicasted ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should multicast the same values to multiple observers' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e1 = cold ( '        -1-2-3----4-|' ) ; const e1subs = '         ^-----------!' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const subscriber1 = hot ( 'a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -1-2-3----4-|' ; const subscriber2 = hot ( '----b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----3----4-|' ; const subscriber3 = hot ( '--------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ----------4-|' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; multicasted . connect ( ) ; } ) ; } ) ; it ( 'should multicast an error from the source to multiple observers' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e1 = cold ( '        -1-2-3----4-#' ) ; const e1subs = '         ^-----------!' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const subscriber1 = hot ( 'a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -1-2-3----4-#' ; const subscriber2 = hot ( '----b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----3----4-#' ; const subscriber3 = hot ( '--------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ----------4-#' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; multicasted . connect ( ) ; } ) ; } ) ; it ( 'should multicast the same values to multiple observers, but is unsubscribed explicitly and early' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e1 = cold ( '        -1-2-3----4-|' ) ; const e1subs = '         ^--------!   ' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const unsub = '          ---------u   ' ; const subscriber1 = hot ( 'a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -1-2-3----   ' ; const subscriber2 = hot ( '----b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----3----   ' ; const subscriber3 = hot ( '--------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ----------   ' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; let connection ; expectObservable ( hot ( unsub ) . pipe ( tap ( ( ) => { connection . unsubscribe ( ) ; } ) ) ) . toBe ( unsub ) ; connection = multicasted . connect ( ) ; } ) ; } ) ; it ( 'should not break unsubscription chains when result is unsubscribed explicitly' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const project = ( x ) => of ( x ) ; const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '        -1-2-3----4-|' ) ; const e1subs = '         ^--------!   ' ; const multicasted = e1 . pipe ( mergeMap ( project ) , multicast ( subjectFactory ) ) as ConnectableObservable < string > ; const subscriber1 = hot ( 'a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      -1-2-3----   ' ; const subscriber2 = hot ( '----b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      -----3----   ' ; const subscriber3 = hot ( '--------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      ----------   ' ; const unsub = '          ---------u   ' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; let connection ; expectObservable ( hot ( unsub ) . pipe ( tap ( ( ) => { connection . unsubscribe ( ) ; } ) ) ) . toBe ( unsub ) ; connection = multicasted . connect ( ) ; } ) ; } ) ; it ( 'should multicast an empty source' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' |   ' ) ; const e1subs = '  (^!)' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const expected = '|   ' ; expectObservable ( multicasted ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; multicasted . connect ( ) ; } ) ; } ) ; it ( 'should multicast a never source' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' -' ) ; const e1subs = '  ^' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const expected = '-' ; expectObservable ( multicasted ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; multicasted . connect ( ) ; } ) ; } ) ; it ( 'should multicast a throw source' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' #   ' ) ; const e1subs = '  (^!)' ; const multicasted = e1 . pipe ( multicast ( ( ) => new Subject < string > ( ) ) ) as ConnectableObservable < string > ; const expected = '#   ' ; expectObservable ( multicasted ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; multicasted . connect ( ) ; } ) ; } ) ; describe ( 'with refCount() and subject factory' , ( ) => { it ( 'should connect when first subscriber subscribes' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '           -1-2-3----4-|' ) ; const e1subs = '         ---^-----------!' ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscriber1 = hot ( '---a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      ----1-2-3----4-|' ; const subscriber2 = hot ( '-------b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      --------3----4-|' ; const subscriber3 = hot ( '-----------c|   ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected3 = '      -------------4-|' ; expectObservable ( subscriber1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 ) . toBe ( expected2 ) ; expectObservable ( subscriber3 ) . toBe ( expected3 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should disconnect when last subscriber unsubscribes' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '           -1-2-3----4-|' ) ; const e1subs = '         ---^--------!   ' ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscriber1 = hot ( '---a|           ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected1 = '      ----1-2-3--     ' ; const unsub1 = '         ----------!     ' ; const subscriber2 = hot ( '-------b|       ' ) . pipe ( mergeMapTo ( multicasted ) ) ; const expected2 = '      --------3----   ' ; const unsub2 = '         ------------!   ' ; expectObservable ( subscriber1 , unsub1 ) . toBe ( expected1 ) ; expectObservable ( subscriber2 , unsub2 ) . toBe ( expected2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be retryable when cold source is synchronous' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '   (123#)          ' ) ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's               ' ; const expected1 = ' (123123123123#) ' ; const subscribe2 = '-s              ' ; const expected2 = ' -(123123123123#)' ; const e1subs = [ '                 (^!)            ' , '                 (^!)            ' , '                 (^!)            ' , '                 (^!)            ' , '                 -(^!)           ' , '                 -(^!)           ' , '                 -(^!)           ' , '                 -(^!)           ' , ] ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 3 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 3 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be retryable with ReplaySubject and cold source is synchronous' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new ReplaySubject ( 1 ) ; const e1 = cold ( '   (123#)          ' ) ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's               ' ; const expected1 = ' (123123123123#) ' ; const subscribe2 = '-s              ' ; const expected2 = ' -(123123123123#)' ; const e1subs = [ '                 (^!)            ' , '                 (^!)            ' , '                 (^!)            ' , '                 (^!)            ' , '                 -(^!)           ' , '                 -(^!)           ' , '                 -(^!)           ' , '                 -(^!)           ' , ] ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 3 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 3 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be repeatable when cold source is synchronous' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '   (123|)             ' ) ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's                  ' ; const expected1 = ' (123123123123123|) ' ; const subscribe2 = '-s                 ' ; const expected2 = ' -(123123123123123|)' ; const e1subs = [ '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , ] ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 5 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 5 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be repeatable with ReplaySubject and cold source is synchronous' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new ReplaySubject ( 1 ) ; const e1 = cold ( '   (123|)             ' ) ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's                  ' ; const expected1 = ' (123123123123123|) ' ; const subscribe2 = '-s                 ' ; const expected2 = ' -(123123123123123|)' ; const e1subs = [ '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 (^!)               ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , '                 -(^!)              ' , ] ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 5 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 5 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be retryable' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject < string > ( ) ; const e1 = cold ( '   -1-2-3----4-#                        ' ) ; const e1subs = [ '                 ^-----------!                        ' , '                 ------------^-----------!            ' , '                 ------------------------^-----------!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's------------------------------------' ; const expected1 = ' -1-2-3----4--1-2-3----4--1-2-3----4-#' ; const subscribe2 = '----s--------------------------------' ; const expected2 = ' -----3----4--1-2-3----4--1-2-3----4-#' ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 2 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( retry ( 2 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be retryable using a ReplaySubject' , ( ) => { testScheduler . run ( ( { cold , time , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new ReplaySubject ( 1 ) ; const e1 = cold ( '        -1-2-3----4-#                        ' ) ; const e1subs = [ '                      ^-----------!                        ' , '                      ------------^-----------!            ' , '                      ------------------------^-----------!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const expected1 = '      -1-2-3----4--1-2-3----4--1-2-3----4-#' ; const subscribe2 = time ( '----|                                ' ) ; const expected2 = '      ----23----4--1-2-3----4--1-2-3----4-#' ; expectObservable ( multicasted . pipe ( retry ( 2 ) ) ) . toBe ( expected1 ) ; testScheduler . schedule ( ( ) => expectObservable ( multicasted . pipe ( retry ( 2 ) ) ) . toBe ( expected2 ) , subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be repeatable' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new Subject ( ) ; const e1 = cold ( '   -1-2-3----4-|                        ' ) ; const e1subs = [ '                 ^-----------!                        ' , '                 ------------^-----------!            ' , '                 ------------------------^-----------!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's------------------------------------' ; const expected1 = ' -1-2-3----4--1-2-3----4--1-2-3----4-|' ; const subscribe2 = '----s--------------------------------' ; const expected2 = ' -----3----4--1-2-3----4--1-2-3----4-|' ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 3 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 3 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should be repeatable using a ReplaySubject' , ( ) => { testScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const subjectFactory = ( ) => new ReplaySubject ( 1 ) ; const e1 = cold ( '   -1-2-3----4-|                        ' ) ; const e1subs = [ '                 ^-----------!                        ' , '                 ------------^-----------!            ' , '                 ------------------------^-----------!' , ] ; const multicasted = e1 . pipe ( multicast ( subjectFactory ) , refCount ( ) ) ; const subscribe1 = 's------------------------------------' ; const expected1 = ' -1-2-3----4--1-2-3----4--1-2-3----4-|' ; const subscribe2 = '----s--------------------------------' ; const expected2 = ' ----23----4--1-2-3----4--1-2-3----4-|' ; expectObservable ( hot ( subscribe1 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 3 ) ) ) . toBe ( expected1 ) ; } ) ) ) . toBe ( subscribe1 ) ; expectObservable ( hot ( subscribe2 ) . pipe ( tap ( ( ) => { expectObservable ( multicasted . pipe ( repeat ( 3 ) ) ) . toBe ( expected2 ) ; } ) ) ) . toBe ( subscribe2 ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; } ) ; it ( 'should multicast one observable to multiple observers' , ( done ) => { const results1 = [ ] ; const results2 = [ ] ; let subscriptions = 0 ; const source = new Observable < number > ( ( observer ) => { subscriptions ++ ; observer . next ( 1 ) ; observer . next ( 2 ) ; observer . next ( 3 ) ; observer . next ( 4 ) ; observer . complete ( ) ; } ) ; const connectable = source . pipe ( multicast ( ( ) => { return new Subject < number > ( ) ; } ) ) as ConnectableObservable < number > ; connectable . subscribe ( ( x ) => { results1 . push ( x ) ; } ) ; connectable . subscribe ( ( x ) => { results2 . push ( x ) ; } ) ; expect ( results1 ) . to . deep . equal ( [ ] ) ; expect ( results2 ) . to . deep . equal ( [ ] ) ; connectable . connect ( ) ; expect ( results1 ) . to . deep . equal ( [ 1 , 2 , 3 , 4 ] ) ; expect ( results2 ) . to . deep . equal ( [ 1 , 2 , 3 , 4 ] ) ; expect ( subscriptions ) . to . equal ( 1 ) ; done ( ) ; } ) ; it ( 'should remove all subscribers from the subject when disconnected' , ( ) => { const subject = new Subject < number > ( ) ; const expected = [ 1 , 2 , 3 , 4 ] ; let i = 0 ; const source = from ( [ 1 , 2 , 3 , 4 ] ) . pipe ( multicast ( subject ) ) as ConnectableObservable < number > ; source . subscribe ( ( x ) => { expect ( x ) . to . equal ( expected [ i ++ ] ) ; } ) ; source . connect ( ) ; expect ( subject . observers . length ) . to . equal ( 0 ) ; } ) ; describe ( 'when given a subject factory' , ( ) => { it ( 'should allow you to reconnect by subscribing again' , ( done ) => { const expected = [ 1 , 2 , 3 , 4 ] ; let i = 0 ; const source = of ( 1 , 2 , 3 , 4 ) . pipe ( multicast ( ( ) => new Subject < number > ( ) ) ) as ConnectableObservable < number > ; source . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected [ i ++ ] ) ; } , complete : ( ) => { i = 0 ; source . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected [ i ++ ] ) ; } , complete : done , } ) ; source . connect ( ) ; } , } ) ; source . connect ( ) ; } ) ; it ( 'should not throw ObjectUnsubscribedError when used in ' + 'a switchMap' , ( done ) => { const source = of ( 1 , 2 , 3 ) . pipe ( multicast ( ( ) => new Subject < number > ( ) ) , refCount ( ) ) ; const expected = [ 'a1' , 'a2' , 'a3' , 'b1' , 'b2' , 'b3' , 'c1' , 'c2' , 'c3' ] ; of ( 'a' , 'b' , 'c' ) . pipe ( switchMap ( ( letter ) => source . pipe ( map ( ( n ) => String ( letter + n ) ) ) ) ) . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { expect ( expected . length ) . to . equal ( 0 ) ; done ( ) ; } , } ) ; } ) ; } ) ; describe ( 'when given a subject' , ( ) => { it ( 'should not throw ObjectUnsubscribedError when used in ' + 'a switchMap' , ( done ) => { const source = of ( 1 , 2 , 3 ) . pipe ( multicast ( new Subject < number > ( ) ) , refCount ( ) ) ; const expected = [ 'a1' , 'a2' , 'a3' ] ; of ( 'a' , 'b' , 'c' ) . pipe ( switchMap ( ( letter ) => source . pipe ( map ( ( n ) => String ( letter + n ) ) ) ) ) . subscribe ( { next : ( x ) => { expect ( x ) . to . equal ( expected . shift ( ) ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { expect ( expected . length ) . to . equal ( 0 ) ; done ( ) ; } , } ) ; } ) ; } ) ; } ) ;