77 Store ,
88 StoreModule ,
99 select ,
10+ ReducerManagerDispatcher ,
11+ UPDATE ,
12+ REDUCER_FACTORY ,
1013} from '../' ;
1114import {
1215 counterReducer ,
@@ -47,56 +50,42 @@ describe('ngRx Store', () => {
4750 describe ( 'initial state' , ( ) => {
4851 it ( 'should handle an initial state object' , ( done : any ) => {
4952 setup ( ) ;
50-
51- store . pipe ( take ( 1 ) ) . subscribe ( {
52- next ( val ) {
53- expect ( val ) . toEqual ( { counter1 : 0 , counter2 : 1 , counter3 : 0 } ) ;
54- } ,
55- error : done ,
56- complete : done ,
57- } ) ;
53+ testStoreValue ( { counter1 : 0 , counter2 : 1 , counter3 : 0 } , done ) ;
5854 } ) ;
5955
6056 it ( 'should handle an initial state function' , ( done : any ) => {
6157 setup ( ( ) => ( { counter1 : 0 , counter2 : 5 } ) ) ;
62-
63- store . pipe ( take ( 1 ) ) . subscribe ( {
64- next ( val ) {
65- expect ( val ) . toEqual ( { counter1 : 0 , counter2 : 5 , counter3 : 0 } ) ;
66- } ,
67- error : done ,
68- complete : done ,
69- } ) ;
58+ testStoreValue ( { counter1 : 0 , counter2 : 5 , counter3 : 0 } , done ) ;
7059 } ) ;
7160
72- function testInitialState ( feature ?: string ) {
73- store = TestBed . get ( Store ) ;
74- dispatcher = TestBed . get ( ActionsSubject ) ;
75-
76- const actionSequence = '--a--b--c--d--e--f--g' ;
77- const stateSequence = 'i-w-----x-----y--z---' ;
78- const actionValues = {
79- a : { type : INCREMENT } ,
80- b : { type : 'OTHER' } ,
81- c : { type : RESET } ,
82- d : { type : 'OTHER' } , // reproduces https://github.com/ngrx/platform/issues/880 because state is falsey
83- e : { type : INCREMENT } ,
84- f : { type : INCREMENT } ,
85- g : { type : 'OTHER' } ,
86- } ;
87- const counterSteps = hot ( actionSequence , actionValues ) ;
88- counterSteps . subscribe ( action => store . dispatch ( action ) ) ;
89-
90- const counterStateWithString = feature
91- ? ( store as any ) . select ( feature , 'counter1' )
92- : store . select ( 'counter1' ) ;
93-
94- const counter1Values = { i : 1 , w : 2 , x : 0 , y : 1 , z : 2 } ;
61+ it ( 'should keep initial state values when state is partially initialized' , ( done : DoneFn ) => {
62+ TestBed . configureTestingModule ( {
63+ imports : [
64+ StoreModule . forRoot ( { } as any , {
65+ initialState : {
66+ feature1 : {
67+ counter1 : 1 ,
68+ } ,
69+ feature3 : {
70+ counter3 : 3 ,
71+ } ,
72+ } ,
73+ } ) ,
74+ StoreModule . forFeature ( 'feature1' , { counter1 : counterReducer } ) ,
75+ StoreModule . forFeature ( 'feature2' , { counter2 : counterReducer } ) ,
76+ StoreModule . forFeature ( 'feature3' , { counter3 : counterReducer } ) ,
77+ ] ,
78+ } ) ;
9579
96- expect ( counterStateWithString ) . toBeObservable (
97- hot ( stateSequence , counter1Values )
80+ testStoreValue (
81+ {
82+ feature1 : { counter1 : 1 } ,
83+ feature2 : { counter2 : 0 } ,
84+ feature3 : { counter3 : 3 } ,
85+ } ,
86+ done
9887 ) ;
99- }
88+ } ) ;
10089
10190 it ( 'should reset to initial state when undefined (root ActionReducerMap)' , ( ) => {
10291 TestBed . configureTestingModule ( {
@@ -138,6 +127,47 @@ describe('ngRx Store', () => {
138127
139128 testInitialState ( 'feature1' ) ;
140129 } ) ;
130+
131+ function testInitialState ( feature ?: string ) {
132+ store = TestBed . get ( Store ) ;
133+ dispatcher = TestBed . get ( ActionsSubject ) ;
134+
135+ const actionSequence = '--a--b--c--d--e--f--g' ;
136+ const stateSequence = 'i-w-----x-----y--z---' ;
137+ const actionValues = {
138+ a : { type : INCREMENT } ,
139+ b : { type : 'OTHER' } ,
140+ c : { type : RESET } ,
141+ d : { type : 'OTHER' } , // reproduces https://github.com/ngrx/platform/issues/880 because state is falsey
142+ e : { type : INCREMENT } ,
143+ f : { type : INCREMENT } ,
144+ g : { type : 'OTHER' } ,
145+ } ;
146+ const counterSteps = hot ( actionSequence , actionValues ) ;
147+ counterSteps . subscribe ( action => store . dispatch ( action ) ) ;
148+
149+ const counterStateWithString = feature
150+ ? ( store as any ) . select ( feature , 'counter1' )
151+ : store . select ( 'counter1' ) ;
152+
153+ const counter1Values = { i : 1 , w : 2 , x : 0 , y : 1 , z : 2 } ;
154+
155+ expect ( counterStateWithString ) . toBeObservable (
156+ hot ( stateSequence , counter1Values )
157+ ) ;
158+ }
159+
160+ function testStoreValue ( expected : any , done : DoneFn ) {
161+ store = TestBed . get ( Store ) ;
162+
163+ store . pipe ( take ( 1 ) ) . subscribe ( {
164+ next ( val ) {
165+ expect ( val ) . toEqual ( expected ) ;
166+ } ,
167+ error : done ,
168+ complete : done ,
169+ } ) ;
170+ }
141171 } ) ;
142172
143173 describe ( 'basic store actions' , ( ) => {
@@ -267,16 +297,19 @@ describe('ngRx Store', () => {
267297 describe ( `add/remove reducers` , ( ) => {
268298 let addReducerSpy : Spy ;
269299 let removeReducerSpy : Spy ;
300+ let reducerManagerDispatcherSpy : Spy ;
270301 const key = 'counter4' ;
271302
272303 beforeEach ( ( ) => {
273304 setup ( ) ;
274305 const reducerManager = TestBed . get ( ReducerManager ) ;
306+ const dispatcher = TestBed . get ( ReducerManagerDispatcher ) ;
275307 addReducerSpy = spyOn ( reducerManager , 'addReducer' ) . and . callThrough ( ) ;
276308 removeReducerSpy = spyOn (
277309 reducerManager ,
278310 'removeReducer'
279311 ) . and . callThrough ( ) ;
312+ reducerManagerDispatcherSpy = spyOn ( dispatcher , 'next' ) . and . callThrough ( ) ;
280313 } ) ;
281314
282315 it ( `should delegate add/remove to ReducerManager` , ( ) => {
@@ -299,5 +332,118 @@ describe('ngRx Store', () => {
299332 expect ( val . counter4 ) . toBeUndefined ( ) ;
300333 } ) ;
301334 } ) ;
335+
336+ it ( 'should dispatch an update reducers action when a reducer is added' , ( ) => {
337+ store . addReducer ( key , counterReducer ) ;
338+ expect ( reducerManagerDispatcherSpy ) . toHaveBeenCalledWith ( {
339+ type : UPDATE ,
340+ feature : key ,
341+ } ) ;
342+ } ) ;
343+
344+ it ( 'should dispatch an update reducers action when a reducer is removed' , ( ) => {
345+ store . removeReducer ( key ) ;
346+ expect ( reducerManagerDispatcherSpy ) . toHaveBeenCalledWith ( {
347+ type : UPDATE ,
348+ feature : key ,
349+ } ) ;
350+ } ) ;
351+ } ) ;
352+
353+ describe ( 'add/remove features' , ( ) => {
354+ let reducerManager : ReducerManager ;
355+ let reducerManagerDispatcherSpy : Spy ;
356+
357+ beforeEach ( ( ) => {
358+ TestBed . configureTestingModule ( {
359+ imports : [ StoreModule . forRoot ( { } ) ] ,
360+ } ) ;
361+
362+ reducerManager = TestBed . get ( ReducerManager ) ;
363+ const dispatcher = TestBed . get ( ReducerManagerDispatcher ) ;
364+ reducerManagerDispatcherSpy = spyOn ( dispatcher , 'next' ) . and . callThrough ( ) ;
365+ } ) ;
366+
367+ it ( 'should dispatch an update reducers action when a feature is added' , ( ) => {
368+ reducerManager . addFeature (
369+ createFeature ( {
370+ key : 'feature1' ,
371+ } )
372+ ) ;
373+
374+ expect ( reducerManagerDispatcherSpy ) . toHaveBeenCalledWith ( {
375+ type : UPDATE ,
376+ feature : 'feature1' ,
377+ } ) ;
378+ } ) ;
379+
380+ it ( 'should dispatch an update reducers action for each feature that is added' , ( ) => {
381+ reducerManager . addFeatures ( [
382+ createFeature ( {
383+ key : 'feature1' ,
384+ } ) ,
385+ createFeature ( {
386+ key : 'feature2' ,
387+ } ) ,
388+ ] ) ;
389+
390+ expect ( reducerManagerDispatcherSpy ) . toHaveBeenCalledTimes ( 2 ) ;
391+
392+ // get the first argument for the first call
393+ expect ( reducerManagerDispatcherSpy . calls . argsFor ( 0 ) [ 0 ] ) . toEqual ( {
394+ type : UPDATE ,
395+ feature : 'feature1' ,
396+ } ) ;
397+
398+ // get the first argument for the second call
399+ expect ( reducerManagerDispatcherSpy . calls . argsFor ( 1 ) [ 0 ] ) . toEqual ( {
400+ type : UPDATE ,
401+ feature : 'feature2' ,
402+ } ) ;
403+ } ) ;
404+
405+ it ( 'should dispatch an update reducers action when a feature is removed' , ( ) => {
406+ reducerManager . removeFeature (
407+ createFeature ( {
408+ key : 'feature1' ,
409+ } )
410+ ) ;
411+
412+ expect ( reducerManagerDispatcherSpy ) . toHaveBeenCalledWith ( {
413+ type : UPDATE ,
414+ feature : 'feature1' ,
415+ } ) ;
416+ } ) ;
417+
418+ it ( 'should dispatch an update reducers action for each feature that is removed' , ( ) => {
419+ reducerManager . removeFeatures ( [
420+ createFeature ( {
421+ key : 'feature1' ,
422+ } ) ,
423+ createFeature ( {
424+ key : 'feature2' ,
425+ } ) ,
426+ ] ) ;
427+
428+ // get the first argument for the first call
429+ expect ( reducerManagerDispatcherSpy . calls . argsFor ( 0 ) [ 0 ] ) . toEqual ( {
430+ type : UPDATE ,
431+ feature : 'feature1' ,
432+ } ) ;
433+
434+ // get the first argument for the second call
435+ expect ( reducerManagerDispatcherSpy . calls . argsFor ( 1 ) [ 0 ] ) . toEqual ( {
436+ type : UPDATE ,
437+ feature : 'feature2' ,
438+ } ) ;
439+ } ) ;
440+
441+ function createFeature ( { key } : { key : string } ) {
442+ return {
443+ key,
444+ reducers : { } ,
445+ reducerFactory : jasmine . createSpy ( `reducerFactory_${ key } ` ) ,
446+ } ;
447+ }
302448 } ) ;
303449} ) ;
0 commit comments