@@ -11,9 +11,11 @@ import {BreakpointObserver, BreakpointState} from './breakpoints-observer';
1111import { MediaMatcher } from './media-matcher' ;
1212import { fakeAsync , TestBed , inject , flush } from '@angular/core/testing' ;
1313import { Injectable } from '@angular/core' ;
14+ import { Subscription } from 'rxjs' ;
15+ import { take } from 'rxjs/operators' ;
1416
1517describe ( 'BreakpointObserver' , ( ) => {
16- let breakpointManager : BreakpointObserver ;
18+ let breakpointObserver : BreakpointObserver ;
1719 let mediaMatcher : FakeMediaMatcher ;
1820
1921 beforeEach ( fakeAsync ( ( ) => {
@@ -26,7 +28,7 @@ describe('BreakpointObserver', () => {
2628 beforeEach ( inject (
2729 [ BreakpointObserver , MediaMatcher ] ,
2830 ( bm : BreakpointObserver , mm : FakeMediaMatcher ) => {
29- breakpointManager = bm ;
31+ breakpointObserver = bm ;
3032 mediaMatcher = mm ;
3133 } ) ) ;
3234
@@ -36,48 +38,48 @@ describe('BreakpointObserver', () => {
3638
3739 it ( 'retrieves the whether a query is currently matched' , fakeAsync ( ( ) => {
3840 const query = 'everything starts as true in the FakeMediaMatcher' ;
39- expect ( breakpointManager . isMatched ( query ) ) . toBeTruthy ( ) ;
41+ expect ( breakpointObserver . isMatched ( query ) ) . toBeTruthy ( ) ;
4042 } ) ) ;
4143
4244 it ( 'reuses the same MediaQueryList for matching queries' , fakeAsync ( ( ) => {
4345 expect ( mediaMatcher . queryCount ) . toBe ( 0 ) ;
44- breakpointManager . observe ( 'query1' ) ;
46+ breakpointObserver . observe ( 'query1' ) ;
4547 expect ( mediaMatcher . queryCount ) . toBe ( 1 ) ;
46- breakpointManager . observe ( 'query1' ) ;
48+ breakpointObserver . observe ( 'query1' ) ;
4749 expect ( mediaMatcher . queryCount ) . toBe ( 1 ) ;
48- breakpointManager . observe ( 'query2' ) ;
50+ breakpointObserver . observe ( 'query2' ) ;
4951 expect ( mediaMatcher . queryCount ) . toBe ( 2 ) ;
50- breakpointManager . observe ( 'query1' ) ;
52+ breakpointObserver . observe ( 'query1' ) ;
5153 expect ( mediaMatcher . queryCount ) . toBe ( 2 ) ;
5254 } ) ) ;
5355
5456 it ( 'splits combined query strings into individual matchMedia listeners' , fakeAsync ( ( ) => {
5557 expect ( mediaMatcher . queryCount ) . toBe ( 0 ) ;
56- breakpointManager . observe ( 'query1, query2' ) ;
58+ breakpointObserver . observe ( 'query1, query2' ) ;
5759 expect ( mediaMatcher . queryCount ) . toBe ( 2 ) ;
58- breakpointManager . observe ( 'query1' ) ;
60+ breakpointObserver . observe ( 'query1' ) ;
5961 expect ( mediaMatcher . queryCount ) . toBe ( 2 ) ;
60- breakpointManager . observe ( 'query2, query3' ) ;
62+ breakpointObserver . observe ( 'query2, query3' ) ;
6163 expect ( mediaMatcher . queryCount ) . toBe ( 3 ) ;
6264 } ) ) ;
6365
6466 it ( 'accepts an array of queries' , fakeAsync ( ( ) => {
6567 const queries = [ '1 query' , '2 query' , 'red query' , 'blue query' ] ;
66- breakpointManager . observe ( queries ) ;
68+ breakpointObserver . observe ( queries ) ;
6769 expect ( mediaMatcher . queryCount ) . toBe ( queries . length ) ;
6870 } ) ) ;
6971
7072 it ( 'completes all events when the breakpoint manager is destroyed' , fakeAsync ( ( ) => {
7173 const firstTest = jasmine . createSpy ( 'test1' ) ;
72- breakpointManager . observe ( 'test1' ) . subscribe ( undefined , undefined , firstTest ) ;
74+ breakpointObserver . observe ( 'test1' ) . subscribe ( undefined , undefined , firstTest ) ;
7375 const secondTest = jasmine . createSpy ( 'test2' ) ;
74- breakpointManager . observe ( 'test2' ) . subscribe ( undefined , undefined , secondTest ) ;
76+ breakpointObserver . observe ( 'test2' ) . subscribe ( undefined , undefined , secondTest ) ;
7577
7678 flush ( ) ;
7779 expect ( firstTest ) . not . toHaveBeenCalled ( ) ;
7880 expect ( secondTest ) . not . toHaveBeenCalled ( ) ;
7981
80- breakpointManager . ngOnDestroy ( ) ;
82+ breakpointObserver . ngOnDestroy ( ) ;
8183 flush ( ) ;
8284
8385 expect ( firstTest ) . toHaveBeenCalled ( ) ;
@@ -87,7 +89,7 @@ describe('BreakpointObserver', () => {
8789 it ( 'emits an event on the observable when values change' , fakeAsync ( ( ) => {
8890 const query = '(width: 999px)' ;
8991 let queryMatchState = false ;
90- breakpointManager . observe ( query ) . subscribe ( ( state : BreakpointState ) => {
92+ breakpointObserver . observe ( query ) . subscribe ( ( state : BreakpointState ) => {
9193 queryMatchState = state . matches ;
9294 } ) ;
9395
@@ -103,7 +105,7 @@ describe('BreakpointObserver', () => {
103105 const queryOne = '(width: 999px)' ;
104106 const queryTwo = '(width: 700px)' ;
105107 let state : BreakpointState = { matches : false , breakpoints : { } } ;
106- breakpointManager . observe ( [ queryOne , queryTwo ] ) . subscribe ( ( breakpoint : BreakpointState ) => {
108+ breakpointObserver . observe ( [ queryOne , queryTwo ] ) . subscribe ( ( breakpoint : BreakpointState ) => {
107109 state = breakpoint ;
108110 } ) ;
109111
@@ -120,38 +122,72 @@ describe('BreakpointObserver', () => {
120122
121123 it ( 'emits a true matches state when the query is matched' , fakeAsync ( ( ) => {
122124 const query = '(width: 999px)' ;
123- breakpointManager . observe ( query ) . subscribe ( ) ;
125+ breakpointObserver . observe ( query ) . subscribe ( ) ;
124126 mediaMatcher . setMatchesQuery ( query , true ) ;
125- expect ( breakpointManager . isMatched ( query ) ) . toBeTruthy ( ) ;
127+ expect ( breakpointObserver . isMatched ( query ) ) . toBeTruthy ( ) ;
126128 } ) ) ;
127129
128130 it ( 'emits a false matches state when the query is not matched' , fakeAsync ( ( ) => {
129131 const query = '(width: 999px)' ;
130- breakpointManager . observe ( query ) . subscribe ( ) ;
132+ breakpointObserver . observe ( query ) . subscribe ( ) ;
131133 mediaMatcher . setMatchesQuery ( query , false ) ;
132- expect ( breakpointManager . isMatched ( query ) ) . toBeFalsy ( ) ;
134+ expect ( breakpointObserver . isMatched ( query ) ) . toBeFalsy ( ) ;
135+ } ) ) ;
136+
137+ it ( 'should not complete other subscribers when preceding subscriber completes' , fakeAsync ( ( ) => {
138+ const queryOne = '(width: 700px)' ;
139+ const queryTwo = '(width: 999px)' ;
140+ const breakpoint = breakpointObserver . observe ( [ queryOne , queryTwo ] ) ;
141+ const subscriptions : Subscription [ ] = [ ] ;
142+ let emittedValues : number [ ] = [ ] ;
143+
144+ subscriptions . push ( breakpoint . subscribe ( ( ) => emittedValues . push ( 1 ) ) ) ;
145+ subscriptions . push ( breakpoint . pipe ( take ( 1 ) ) . subscribe ( ( ) => emittedValues . push ( 2 ) ) ) ;
146+ subscriptions . push ( breakpoint . subscribe ( ( ) => emittedValues . push ( 3 ) ) ) ;
147+ subscriptions . push ( breakpoint . subscribe ( ( ) => emittedValues . push ( 4 ) ) ) ;
148+
149+ mediaMatcher . setMatchesQuery ( queryOne , true ) ;
150+ mediaMatcher . setMatchesQuery ( queryTwo , false ) ;
151+ flush ( ) ;
152+
153+ expect ( emittedValues ) . toEqual ( [ 1 , 2 , 3 , 4 ] ) ;
154+ emittedValues = [ ] ;
155+
156+ mediaMatcher . setMatchesQuery ( queryOne , false ) ;
157+ mediaMatcher . setMatchesQuery ( queryTwo , true ) ;
158+ flush ( ) ;
159+
160+ expect ( emittedValues ) . toEqual ( [ 1 , 3 , 4 ] ) ;
161+
162+ subscriptions . forEach ( subscription => subscription . unsubscribe ( ) ) ;
133163 } ) ) ;
134164} ) ;
135165
136166export class FakeMediaQueryList {
137167 /** The callback for change events. */
138- addListenerCallback ? : ( mql : MediaQueryListEvent ) => void ;
168+ private _listeners : ( ( mql : MediaQueryListEvent ) => void ) [ ] = [ ] ;
139169
140170 constructor ( public matches : boolean , public media : string ) { }
141171
142172 /** Toggles the matches state and "emits" a change event. */
143173 setMatches ( matches : boolean ) {
144174 this . matches = matches ;
145- this . addListenerCallback ! ( this as any ) ;
175+ this . _listeners . forEach ( listener => listener ( this as any ) ) ;
146176 }
147177
148- /** Registers the callback method for change events. */
178+ /** Registers a callback method for change events. */
149179 addListener ( callback : ( mql : MediaQueryListEvent ) => void ) {
150- this . addListenerCallback = callback ;
180+ this . _listeners . push ( callback ) ;
151181 }
152182
153- // Noop removal method for testing.
154- removeListener ( ) { }
183+ /** Removes a callback method from the change events. */
184+ removeListener ( callback : ( mql : MediaQueryListEvent ) => void ) {
185+ const index = this . _listeners . indexOf ( callback ) ;
186+
187+ if ( index > - 1 ) {
188+ this . _listeners . splice ( index , 1 ) ;
189+ }
190+ }
155191}
156192
157193@Injectable ( )
0 commit comments