prettier import { expect } from 'chai' ; import { tap , mergeMap , take } from 'rxjs/operators' ; import { Subject , of , throwError , Observer , EMPTY , Observable , noop } from 'rxjs' ; import { TestScheduler } from 'rxjs/testing' ; import { observableMatcher } from '../helpers/observableMatcher' ; test describe ( 'tap' , ( ) => { let testScheduler ; beforeEach ( ( ) => { testScheduler = new TestScheduler ( observableMatcher ) ; } ) ; it ( 'should mirror multiple values and complete' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --1--2--3--|' ) ; const e1subs = '  ^----------!' ; const expected = '--1--2--3--|' ; const result = e1 . pipe ( tap ( ( ) => { } ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should next with a callback' , ( ) => { let value = null ; of ( 42 ) . pipe ( tap ( function ( x ) { value = x ; } ) ) . subscribe ( ) ; expect ( value ) . to . equal ( 42 ) ; } ) ; it ( 'should error with a callback' , ( ) => { let err = null ; throwError ( ( ) => 'bad' ) . pipe ( tap ( { error : function ( x ) { err = x ; } , } ) ) . subscribe ( { error ( ex ) { expect ( ex ) . to . equal ( 'bad' ) ; } , } ) ; expect ( err ) . to . equal ( 'bad' ) ; } ) ; it ( 'should handle everything with an observer' , ( done ) => { const expected = [ 1 , 2 , 3 ] ; const results = [ ] ; of ( 1 , 2 , 3 ) . pipe ( tap ( < Observer < number > > { next : ( x ) => { results . push ( x ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { expect ( results ) . to . deep . equal ( expected ) ; done ( ) ; } , } ) ) . subscribe ( ) ; } ) ; it ( 'should handle everything with a Subject' , ( done ) => { const expected = [ 1 , 2 , 3 ] ; const results = [ ] ; const subject = new Subject < number > ( ) ; subject . subscribe ( { next : ( x ) => { results . push ( x ) ; } , error : ( ) => { done ( new Error ( 'should not be called' ) ) ; } , complete : ( ) => { expect ( results ) . to . deep . equal ( expected ) ; done ( ) ; } , } ) ; of ( 1 , 2 , 3 ) . pipe ( tap ( subject ) ) . subscribe ( ) ; } ) ; it ( 'should handle an error with a callback' , ( ) => { let errored = false ; throwError ( ( ) => 'bad' ) . pipe ( tap ( { error : ( err ) => { expect ( err ) . to . equal ( 'bad' ) ; } , } ) ) . subscribe ( { error ( err ) { errored = true ; expect ( err ) . to . equal ( 'bad' ) ; } , } ) ; expect ( errored ) . to . be . true ; } ) ; it ( 'should handle an error with observer' , ( ) => { let errored = false ; throwError ( ( ) => 'bad' ) . pipe ( tap ( < any > { error : function ( err ) { expect ( err ) . to . equal ( 'bad' ) ; } , } ) ) . subscribe ( { error ( err ) { errored = true ; expect ( err ) . to . equal ( 'bad' ) ; } , } ) ; expect ( errored ) . to . be . true ; } ) ; it ( 'should handle complete with observer' , ( ) => { let completed = false ; EMPTY . pipe ( tap ( < any > { complete : ( ) => { completed = true ; } , } ) ) . subscribe ( ) ; expect ( completed ) . to . be . true ; } ) ; it ( 'should handle next with observer' , ( ) => { let value = null ; of ( 'hi' ) . pipe ( tap ( < any > { next : ( x ) => { value = x ; } , } ) ) . subscribe ( ) ; expect ( value ) . to . equal ( 'hi' ) ; } ) ; it ( 'should raise error if next handler raises error' , ( ) => { of ( 'hi' ) . pipe ( tap ( < any > { next : ( ) => { throw new Error ( 'bad' ) ; } , } ) ) . subscribe ( { error ( err ) { expect ( err . message ) . to . equal ( 'bad' ) ; } , } ) ; } ) ; it ( 'should raise error if error handler raises error' , ( ) => { throwError ( ( ) => 'ops' ) . pipe ( tap ( < any > { error : ( ) => { throw new Error ( 'bad' ) ; } , } ) ) . subscribe ( { error ( err ) { expect ( err . message ) . to . equal ( 'bad' ) ; } , } ) ; } ) ; it ( 'should raise error if complete handler raises error' , ( ) => { EMPTY . pipe ( tap ( < any > { complete : ( ) => { throw new Error ( 'bad' ) ; } , } ) ) . subscribe ( { error ( err ) { expect ( err . message ) . to . equal ( 'bad' ) ; } , } ) ; } ) ; it ( 'should allow unsubscribing explicitly and early' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  --1--2--3--#' ) ; const unsub = '   -------!    ' ; const e1subs = '  ^------!    ' ; const expected = '--1--2--    ' ; const result = e1 . pipe ( tap ( ( ) => { } ) ) ; expectObservable ( result , unsub ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not break unsubscription chains when result is unsubscribed explicitly' , ( ) => { testScheduler . run ( ( { hot , expectObservable , expectSubscriptions } ) => { const e1 = hot ( '  --1--2--3--#' ) ; const e1subs = '  ^------!    ' ; const expected = '--1--2--    ' ; const unsub = '   -------!    ' ; const result = e1 . pipe ( mergeMap ( ( x ) => of ( x ) ) , tap ( ( ) => { } ) , mergeMap ( ( x ) => of ( x ) ) ) ; expectObservable ( result , unsub ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mirror multiple values and complete' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --1--2--3--|' ) ; const e1subs = '  ^----------!' ; const expected = '--1--2--3--|' ; const result = e1 . pipe ( tap ( ( ) => { } ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should mirror multiple values and terminate with error' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --1--2--3--#' ) ; const e1subs = '  ^----------!' ; const expected = '--1--2--3--#' ; const result = e1 . pipe ( tap ( ( ) => { } ) ) ; expectObservable ( result ) . toBe ( expected ) ; 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 ( tap ( ( ) => { } ) , take ( 3 ) ) . subscribe ( ( ) => { } ) ; expect ( sideEffects ) . to . deep . equal ( [ 0 , 1 , 2 ] ) ; } ) ; describe ( 'lifecycle handlers' , ( ) => { it ( 'should support an unsubscribe event that fires before finalize' , ( ) => { const results = [ ] ; const subject = new Subject < number > ( ) ; const subscription = subject . pipe ( tap ( { subscribe : ( ) => results . push ( 'subscribe' ) , next : ( value ) => results . push ( `next ${ value }` ) , error : ( err ) => results . push ( `error: ${ err . message }` ) , complete : ( ) => results . push ( 'complete' ) , unsubscribe : ( ) => results . push ( 'unsubscribe' ) , finalize : ( ) => results . push ( 'finalize' ) , } ) ) . subscribe ( ) ; subject . next ( 1 ) ; subject . next ( 2 ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' ] ) ; subscription . unsubscribe ( ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' , 'unsubscribe' , 'finalize' ] ) ; } ) ; it ( 'should not call unsubscribe if source completes' , ( ) => { const results = [ ] ; const subject = new Subject < number > ( ) ; const subscription = subject . pipe ( tap ( { subscribe : ( ) => results . push ( 'subscribe' ) , next : ( value ) => results . push ( `next ${ value }` ) , error : ( err ) => results . push ( `error: ${ err . message }` ) , complete : ( ) => results . push ( 'complete' ) , unsubscribe : ( ) => results . push ( 'unsubscribe' ) , finalize : ( ) => results . push ( 'finalize' ) , } ) ) . subscribe ( ) ; subject . next ( 1 ) ; subject . next ( 2 ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' ] ) ; subject . complete ( ) ; subscription . unsubscribe ( ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' , 'complete' , 'finalize' ] ) ; } ) ; it ( 'should not call unsubscribe if source errors' , ( ) => { const results = [ ] ; const subject = new Subject < number > ( ) ; const subscription = subject . pipe ( tap ( { subscribe : ( ) => results . push ( 'subscribe' ) , next : ( value ) => results . push ( `next ${ value }` ) , error : ( err ) => results . push ( `error: ${ err . message }` ) , complete : ( ) => results . push ( 'complete' ) , unsubscribe : ( ) => results . push ( 'unsubscribe' ) , finalize : ( ) => results . push ( 'finalize' ) , } ) ) . subscribe ( { error : noop , } ) ; subject . next ( 1 ) ; subject . next ( 2 ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' ] ) ; subject . error ( new Error ( 'bad' ) ) ; subscription . unsubscribe ( ) ; expect ( results ) . to . deep . equal ( [ 'subscribe' , 'next 1' , 'next 2' , 'error: bad' , 'finalize' ] ) ; } ) ; } ) ; } ) ;