prettier import { expect } from 'chai' ; import { TestScheduler } from 'rxjs/internal/testing/TestScheduler' ; import { pluck , map , mergeMap , take } from 'rxjs/operators' ; import { of , Observable } from 'rxjs' ; import { observableMatcher } from '../helpers/observableMatcher' ; test describe ( 'pluck' , ( ) => { let testScheduler ; beforeEach ( ( ) => { testScheduler = new TestScheduler ( observableMatcher ) ; } ) ; it ( 'should dematerialize an Observable' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : '{v:1}' , b : '{v:2}' , c : '{v:3}' , } ; const e1 = cold ( ' --a--b--c--|' , inputs ) ; const e1subs = '  ^----------!' ; const expected = '--x--y--z--|' ; const result = e1 . pipe ( map ( ( x ) => ( { v : x . charAt ( 3 ) } ) ) , pluck ( 'v' ) ) ; expectObservable ( result ) . toBe ( expected , { x : '1' , y : '2' , z : '3' } ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should work for one array' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { x : [ 'abc' ] } ; const e1 = cold ( ' --x--|' , inputs ) ; const e1subs = '  ^----!' ; const expected = '--y--|' ; const result = e1 . pipe ( pluck ( 0 ) ) ; expectObservable ( result ) . toBe ( expected , { y : 'abc' } ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should work for one object' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { x : { prop : 42 } } ; const e1 = cold ( ' --x--|' , inputs ) ; const e1subs = '  ^----!' ; const expected = '--y--|' ; const result = e1 . pipe ( pluck ( 'prop' ) ) ; expectObservable ( result ) . toBe ( expected , { y : 42 } ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should work for multiple objects' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { prop : '1' } , b : { prop : '2' } , c : { prop : '3' } , d : { prop : '4' } , e : { prop : '5' } , } ; const e1 = cold ( ' --a-b--c-d---e-|' , inputs ) ; const e1subs = '  ^--------------!' ; const expected = '--1-2--3-4---5-|' ; const result = e1 . pipe ( pluck ( 'prop' ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should work with deep nested properties' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { a : { b : { c : '1' } } } , b : { a : { b : { c : '2' } } } , c : { a : { b : { c : '3' } } } , d : { a : { b : { c : '4' } } } , e : { a : { b : { c : '5' } } } , } ; const e1 = cold ( ' --a-b--c-d---e-|' , inputs ) ; const e1subs = '  ^--------------!' ; const expected = '--1-2--3-4---5-|' ; const result = e1 . pipe ( pluck ( 'a' , 'b' , 'c' ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should work with edge cases of deep nested properties' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { i : { j : { k : 1 } } } , b : { i : { j : 2 } } , c : { i : { k : { k : 3 } } } , d : { } , e : { i : { j : { k : 5 } } } , } ; const e1 = cold ( ' --a-b--c-d---e-|' , inputs ) ; const e1subs = '  ^--------------!' ; const expected = '--v-w--x-y---z-|' ; const values = { v : 1 , w : undefined , x : undefined , y : undefined , z : 5 } ; const result = e1 . pipe ( pluck ( 'i' , 'j' , 'k' ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should throw an error if not property is passed' , ( ) => { expect ( ( ) => { of ( { prop : 1 } , { prop : 2 } ) . pipe ( pluck ( ) ) ; } ) . to . throw ( Error , 'list of properties cannot be empty.' ) ; } ) ; it ( 'should propagate errors from observable that emits only errors' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' #   ' ) ; const e1subs = '  (^!)' ; const expected = '#   ' ; const result = e1 . pipe ( pluck ( 'whatever' ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should propagate errors from observable that emit values' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { prop : '1' } , b : { prop : '2' } } ; const e1 = cold ( ' --a--b--#' , inputs , 'too bad' ) ; const e1subs = '  ^-------!' ; const expected = '--1--2--#' ; const result = e1 . pipe ( pluck ( 'prop' ) ) ; expectObservable ( result ) . toBe ( expected , undefined , 'too bad' ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not pluck an empty observable' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' |   ' ) ; const e1subs = '  (^!)' ; const expected = '|   ' ; const result = e1 . pipe ( pluck ( 'whatever' ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should allow unsubscribing explicitly and early' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e1 = cold ( ' --a--b--c--|' , { a : { prop : '1' } , b : { prop : '2' } } ) ; const e1subs = '  ^-----!     ' ; const expected = '--1--2-     ' ; const unsub = '   ------!     ' ; const result = e1 . pipe ( pluck ( 'prop' ) ) ; expectObservable ( result , unsub ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should pluck twice' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { a : { b : { c : '1' } } } , b : { a : { b : { c : '2' } } } , c : { a : { b : { c : '3' } } } , d : { a : { b : { c : '4' } } } , e : { a : { b : { c : '5' } } } , } ; const e1 = cold ( ' --a-b--c-d---e-|' , inputs ) ; const e1subs = '  ^--------------!' ; const expected = '--1-2--3-4---5-|' ; const result = e1 . pipe ( pluck ( 'a' , 'b' ) , pluck ( 'c' ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not break unsubscription chain when unsubscribed explicitly' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { a : { prop : '1' } , b : { prop : '2' } } ; const e1 = cold ( ' --a--b--c--|' , inputs ) ; const e1subs = '  ^-----!     ' ; const expected = '--1--2-     ' ; const unsub = '   ------!     ' ; const result = e1 . pipe ( mergeMap ( ( x ) => of ( x ) ) , pluck ( 'prop' ) , mergeMap ( ( x ) => of ( x ) ) ) ; expectObservable ( result , unsub ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should support symbols' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const sym = Symbol ( 'sym' ) ; const inputs = { x : { [ sym ] : 'abc' } } ; const e1 = cold ( ' --x--|' , inputs ) ; const e1subs = '  ^----!' ; const expected = '--y--|' ; const result = e1 . pipe ( pluck ( sym ) ) ; expectObservable ( result ) . toBe ( expected , { y : 'abc' } ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; } ) ; } ) ; it ( 'should not break on null values' , ( ) => { testScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const inputs = { x : null } ; const e1 = cold ( ' --x--|' , inputs ) ; const e1subs = '  ^----!' ; const expected = '--y--|' ; const result = e1 . pipe ( pluck ( 'prop' ) ) ; expectObservable ( result ) . toBe ( expected , { y : undefined } ) ; 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 ( pluck ( 'whatever' ) , take ( 3 ) ) . subscribe ( ( ) => { } ) ; expect ( sideEffects ) . to . deep . equal ( [ 0 , 1 , 2 ] ) ; } ) ; } ) ;