prettier import { expect } from 'chai' ; import { Observable , NEVER , of , ObjectUnsubscribedError , EMPTY } from 'rxjs' ; import { windowToggle , tap , mergeMap } from 'rxjs/operators' ; import { TestScheduler } from 'rxjs/testing' ; import { observableMatcher } from '../helpers/observableMatcher' ; test describe ( 'windowToggle' , ( ) => { let rxTestScheduler ; beforeEach ( ( ) => { rxTestScheduler = new TestScheduler ( observableMatcher ) ; } ) ; it ( 'should emit windows governed by openings and closings' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '         ----w--------w--------w--|' ) ; const e2subs = '          ^------------------------!' ; const e3 = cold ( '             -----x                ' ) ; const e3subs = [ '                       ----^----!                ' , '                       -------------^----!       ' , '                       ----------------------^--!' , ] ; const e1 = hot ( '  --1--2--^-a--b--c--d--e--f--g--h-|' ) ; const e1subs = '          ^------------------------!' ; const expected = '        ----x--------y--------z--|' ; const x = cold ( '              -b--c|                ' ) ; const y = cold ( '                       -e--f|       ' ) ; const z = cold ( '                                -h-|' ) ; const values = { x , y , z } ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( e3 . subscriptions ) . toBe ( e3subs ) ; } ) ; } ) ; it ( 'should emit windows that are opened by an observable from the first argument and closed by an observable returned by the function in the second argument' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '       --------x-------x-------x--|' ) ; const e2subs = '        ^--------------------------!' ; const e3 = cold ( '               ----------(x|)      ' ) ; const e3subs = [ '                     --------^---------!         ' , '                     ----------------^---------! ' , '                     ------------------------^--!' , ] ; const e1 = hot ( '--1--2--^--a--b--c--d--e--f--g--h--|' ) ; const e1subs = '        ^--------------------------!' ; const expected = '      --------x-------y-------z--|' ; const x = cold ( '                -c--d--e--(f|)      ' ) ; const y = cold ( '                        --f--g--h-| ' ) ; const z = cold ( '                                ---|' ) ; const values = { x , y , z } ; const source = e1 . pipe ( windowToggle ( e2 , ( value ) => { expect ( value ) . to . equal ( 'x' ) ; return e3 ; } ) ) ; expectObservable ( source ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( e3 . subscriptions ) . toBe ( e3subs ) ; } ) ; } ) ; it ( 'should emit windows using varying cold closings' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|            ' ) ; const e2subs = '     ^--------------------------!            ' ; const close = [ cold ( '               ---------------s--|                   ' ) , cold ( '                           ----(s|)                  ' ) , cold ( '                                  ---------------(s|)' ) , ] ; const closeSubs = [ '                  --^--------------!                      ' , '                  --------------^---!                     ' , '                  -----------------------^-----------!    ' , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|    ' ) ; const e1subs = '     ^----------------------------------!    ' ; const expected = '   --x-----------y--------z-----------|    ' ; const x = cold ( '       --b---c---d---e|                      ' ) ; const y = cold ( '                   --e-|                     ' ) ; const z = cold ( '                            -g---h------|    ' ) ; const values = { x , y , z } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( close [ 0 ] . subscriptions ) . toBe ( closeSubs [ 0 ] ) ; expectSubscriptions ( close [ 1 ] . subscriptions ) . toBe ( closeSubs [ 1 ] ) ; expectSubscriptions ( close [ 2 ] . subscriptions ) . toBe ( closeSubs [ 2 ] ) ; } ) ; } ) ; it ( 'should emit windows using varying hot closings' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|           ' ) ; const e2subs = '     ^--------------------------!           ' ; const closings = [ hot ( '          -1--^----------------s-|                   ' ) , hot ( '              -----3----4-------(s|)                 ' ) , hot ( '              -------3----4-------5----------------s|' ) , ] ; const closingSubs = [ '                  --^--------------!                     ' , '                  --------------^---!                    ' , '                  -----------------------^-----------!   ' , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|   ' ) ; const e1subs = '     ^----------------------------------!   ' ; const expected = '   --x-----------y--------z-----------|   ' ; const x = cold ( '       --b---c---d---e|                     ' ) ; const y = cold ( '                   --e-|                    ' ) ; const z = cold ( '                            -g---h------|   ' ) ; const values = { x , y , z } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => closings [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( closings [ 0 ] . subscriptions ) . toBe ( closingSubs [ 0 ] ) ; expectSubscriptions ( closings [ 1 ] . subscriptions ) . toBe ( closingSubs [ 1 ] ) ; expectSubscriptions ( closings [ 2 ] . subscriptions ) . toBe ( closingSubs [ 2 ] ) ; } ) ; } ) ; it ( 'should emit windows using varying empty delayed closings' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|           ' ) ; const e2subs = '     ^--------------------------!           ' ; const close = [ cold ( '               ---------------|                     ' ) , cold ( '                           ----|                    ' ) , cold ( '                                    ---------------|' ) , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|   ' ) ; const e1subs = '     ^----------------------------------!   ' ; const expected = '   --x-----------y--------z-----------|   ' ; const x = cold ( '       --b---c---d---e---f---g---h------|   ' ) ; const y = cold ( '                   --e---f---g---h------|   ' ) ; const z = cold ( '                            -g---h------|   ' ) ; const values = { x , y , z } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should emit windows using varying cold closings, outer unsubscribed early' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|              ' ) ; const e2subs = '     ^----------------!                        ' ; const close = [ cold ( '               -------------s---|                      ' ) , cold ( '                           -----(s|)                   ' ) , cold ( '                                    ---------------(s|)' ) , ] ; const closeSubs = [ '                  --^------------!                          ' , '                  --------------^--!                        ' , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|      ' ) ; const e1subs = '     ^----------------!                        ' ; const expected = '   --x-----------y---                        ' ; const x = cold ( '       --b---c---d--|                          ' ) ; const y = cold ( '                   --e-                        ' ) ; const unsub = '      -----------------!                        ' ; const values = { x , y } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result , unsub ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( close [ 0 ] . subscriptions ) . toBe ( closeSubs [ 0 ] ) ; expectSubscriptions ( close [ 1 ] . subscriptions ) . toBe ( closeSubs [ 1 ] ) ; expectSubscriptions ( close [ 2 ] . subscriptions ) . toBe ( [ ] ) ; } ) ; } ) ; it ( 'should not break unsubscription chains when result is unsubscribed explicitly' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|              ' ) ; const e2subs = '     ^--------------!                          ' ; const close = [ cold ( '               ---------------s--|                     ' ) , cold ( '                           ----(s|)                    ' ) , cold ( '                                    ---------------(s|)' ) , ] ; const closeSubs = [ '                  --^------------!                          ' , '                  --------------^!                          ' , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|      ' ) ; const e1subs = '     ^--------------!                          ' ; const expected = '   --x-----------y-                          ' ; const x = cold ( '       --b---c---d---                          ' ) ; const y = cold ( '                   --                          ' ) ; const unsub = '      ---------------!                          ' ; const values = { x , y } ; let i = 0 ; const result = e1 . pipe ( mergeMap ( ( x ) => of ( x ) ) , windowToggle ( e2 , ( ) => close [ i ++ ] ) , mergeMap ( ( x ) => of ( x ) ) ) ; expectObservable ( result , unsub ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; expectSubscriptions ( close [ 0 ] . subscriptions ) . toBe ( closeSubs [ 0 ] ) ; expectSubscriptions ( close [ 1 ] . subscriptions ) . toBe ( closeSubs [ 1 ] ) ; } ) ; } ) ; it ( 'should dispose window Subjects if the outer is unsubscribed early' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions , time } ) => { const open = cold ( ' o-------------------------|' ) ; const e1 = hot ( '    --a--b--c--d--e--f--g--h--|' ) ; const e1subs = '    ^--------!                 ' ; const expected = '  x---------                 ' ; const x = cold ( '    --a--b--c-                 ' ) ; const unsub = '     ---------!                 ' ; const late = time ( ' ---------------|           ' ) ; const values = { x } ; let window ; const result = e1 . pipe ( windowToggle ( open , ( ) => NEVER ) , tap ( ( w ) => { window = w ; } ) ) ; expectObservable ( result , unsub ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; rxTestScheduler . schedule ( ( ) => { expect ( ( ) => { window . subscribe ( ) ; } ) . to . throw ( ObjectUnsubscribedError ) ; } , late ) ; } ) ; } ) ; it ( 'should propagate error thrown from closingSelector' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|              ' ) ; const e2subs = '     ^-------------!                           ' ; const close = [ cold ( '               ---------------s--|                     ' ) , cold ( '                           ----(s|)                    ' ) , cold ( '                                    ---------------(s|)' ) , ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|      ' ) ; const e1subs = '     ^-------------!                           ' ; const expected = '   --x-----------#----                       ' ; const x = cold ( '       --b---c---d-#                           ' ) ; const values = { x : x } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => { if ( i === 1 ) { throw 'error' ; } return close [ i ++ ] ; } ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should propagate error emitted from a closing' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|        ' ) ; const e2subs = '     ^-------------!                     ' ; const close = [ cold ( '               ---------------s--|               ' ) , cold ( '                           #                     ' ) ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     ^-------------!                     ' ; const expected = '   --x-----------(y#)                  ' ; const x = cold ( '       --b---c---d-#                     ' ) ; const y = cold ( '                   #                     ' ) ; const values = { x , y } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should propagate error emitted late from a closing' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|        ' ) ; const e2subs = '     ^------------------!                ' ; const close = [ cold ( '               ---------------s--|               ' ) , cold ( '                           -----#                ' ) ] ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     ^------------------!                ' ; const expected = '   --x-----------y----#                ' ; const x = cold ( '       --b---c---d---e|                  ' ) ; const y = cold ( '                   --e--#                ' ) ; const values = { x , y } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle errors' , ( ) => { rxTestScheduler . run ( ( { hot , cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    --x-----------y--------z---|        ' ) ; const e2subs = '     ^------------------!                ' ; const close = [ cold ( '               ---------------s--|               ' ) , cold ( '                           -------s|             ' ) ] ; const e1 = hot ( '--a--^---b---c---d---e--#                ' ) ; const e1subs = '     ^------------------!                ' ; const expected = '   --x-----------y----#                ' ; const x = cold ( '       --b---c---d---e|                  ' ) ; const y = cold ( '                   --e--#                ' ) ; const values = { x , y } ; let i = 0 ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => close [ i ++ ] ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle empty source' , ( ) => { rxTestScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '--o-----|' ) ; const e2subs = '   (^!)' ; const e3 = cold ( '  -----c--|' ) ; const e1 = cold ( '  |' ) ; const e1subs = '   (^!)' ; const expected = ' |' ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle throw' , ( ) => { rxTestScheduler . run ( ( { cold , expectObservable , expectSubscriptions } ) => { const e2 = cold ( ' --o-----|' ) ; const e2subs = '  (^!)' ; const e3 = cold ( ' -----c--|' ) ; const e1 = cold ( ' #' ) ; const e1subs = '  (^!)' ; const expected = '#' ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle never' , ( ) => { rxTestScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e2 = cold ( ' --o-----o------o-----o---o-----|             ' ) ; const e2subs = '  ^------------------------------!             ' ; const e3 = cold ( '   --c-|                                      ' ) ; const e1 = hot ( '  -                                            ' ) ; const e1subs = '  ^-------------------------------------------!' ; const expected = '--u-----v------x-----y---z-------------------' ; const u = cold ( '    --|                                        ' ) ; const v = cold ( '          --|                                  ' ) ; const x = cold ( '                 --|                           ' ) ; const y = cold ( '                       --|                     ' ) ; const z = cold ( '                           --|                 ' ) ; const unsub = '   --------------------------------------------!' ; const values = { u : u , v : v , x , y , z } ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result , unsub ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle a never opening Observable' , ( ) => { rxTestScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    -                                   ' ) ; const e2subs = '     ^----------------------------------!' ; const e3 = cold ( '    --c-|                               ' ) ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     ^----------------------------------!' ; const expected = '   -----------------------------------|' ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle a never closing Observable' , ( ) => { rxTestScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    ---o---------------o-----------|    ' ) ; const e2subs = '     ^------------------------------!    ' ; const e3 = cold ( '       -                                ' ) ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     ^----------------------------------!' ; const expected = '   ---x---------------y---------------|' ; const x = cold ( '        -b---c---d---e---f---g---h------|' ) ; const y = cold ( '                        -f---g---h------|' ) ; const values = { x , y } ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle opening Observable that just throws' , ( ) => { rxTestScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    #                                   ' ) ; const e2subs = '     (^!)                                ' ; const e3 = cold ( '    --c-|                               ' ) ; const subs = '       (^!)                                ' ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     (^!)                                ' ; const expected = '   #                                   ' ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( subs ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; it ( 'should handle empty closing observable' , ( ) => { rxTestScheduler . run ( ( { cold , hot , expectObservable , expectSubscriptions } ) => { const e2 = cold ( '    ---o---------------o-----------|    ' ) ; const e2subs = '     ^------------------------------!    ' ; const e3 = EMPTY ; const e1 = hot ( '--a--^---b---c---d---e---f---g---h------|' ) ; const e1subs = '     ^----------------------------------!' ; const expected = '   ---x---------------y---------------|' ; const x = cold ( '        -b---c---d---e---f---g---h------|' ) ; const y = cold ( '                        -f---g---h------|' ) ; const values = { x , y } ; const result = e1 . pipe ( windowToggle ( e2 , ( ) => e3 ) ) ; expectObservable ( result ) . toBe ( expected , values ) ; expectSubscriptions ( e1 . subscriptions ) . toBe ( e1subs ) ; expectSubscriptions ( e2 . subscriptions ) . toBe ( e2subs ) ; } ) ; } ) ; } ) ;