From 0a52de91da9f8fb5be625ccbd98bc4f258071897 Mon Sep 17 00:00:00 2001 From: Reko Jokelainen Date: Tue, 8 Aug 2017 11:48:37 +0300 Subject: [PATCH 1/2] fix(utils): meta reducers conflicting with initial state Closes #247 --- modules/store/spec/modules.spec.ts | 33 +++++++++++++++ modules/store/spec/utils.spec.ts | 65 +++++++++++++++++++++++++++++- modules/store/src/utils.ts | 2 +- 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/modules/store/spec/modules.spec.ts b/modules/store/spec/modules.spec.ts index 5a6690c691..019896fbb0 100644 --- a/modules/store/spec/modules.spec.ts +++ b/modules/store/spec/modules.spec.ts @@ -119,6 +119,39 @@ describe(`Store Modules`, () => { }); }); + describe(`: With initial state`, () => { + const initialState: RootState = { fruit: 'banana' }; + const reducerMap: ActionReducerMap = { fruit: rootFruitReducer }; + const noopMetaReducer = (r: Function) => (state: any, action: any) => { + return r(state, action); + }; + + const testWithMetaReducers = (metaReducers: any[]) => () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot(reducerMap, { initialState, metaReducers }), + ], + }); + store = TestBed.get(Store); + }); + it('should have initial state', () => { + store.take(1).subscribe((s: any) => { + expect(s).toEqual(initialState); + }); + }); + }; + + describe( + 'should add initial state with no meta reducers', + testWithMetaReducers([]) + ); + describe( + 'should add initial state with a simple no-op meta reducer', + testWithMetaReducers([noopMetaReducer]) + ); + }); + describe(`: Nested`, () => { @NgModule({ imports: [StoreModule.forFeature('a', featureAReducer)], diff --git a/modules/store/spec/utils.spec.ts b/modules/store/spec/utils.spec.ts index 9b2cd7ea28..63d6407198 100644 --- a/modules/store/spec/utils.spec.ts +++ b/modules/store/spec/utils.spec.ts @@ -1,5 +1,11 @@ import { omit } from '../src/utils'; -import { combineReducers, compose } from '@ngrx/store'; +import { + ActionReducer, + ActionReducerMap, + combineReducers, + compose, + createReducerFactory, +} from '@ngrx/store'; describe(`Store utils`, () => { describe(`combineReducers()`, () => { @@ -73,4 +79,61 @@ describe(`Store utils`, () => { expect(id(1)).toBe(1); }); }); + + describe(`createReducerFactory()`, () => { + const fruitReducer = (state: string = 'banana', action: any) => + action.type === 'fruit' ? action.payload : state; + type FruitState = { fruit: string }; + const reducerMap: ActionReducerMap = { fruit: fruitReducer }; + const initialState: FruitState = { fruit: 'apple' }; + + const runWithExpectations = ( + metaReducers: any[], + initialState: any, + expectedState: any + ) => () => { + let spiedFactory: jasmine.Spy; + let reducer: ActionReducer; + beforeEach(() => { + spiedFactory = jasmine + .createSpy('spied factory') + .and.callFake(combineReducers); + reducer = createReducerFactory(spiedFactory, metaReducers)( + reducerMap, + initialState + ); + }); + it(`should pass the reducers and initialState to the factory method`, () => { + expect(spiedFactory).toHaveBeenCalledWith(reducerMap, initialState); + }); + it(`should return the expected initialState`, () => { + expect(reducer(undefined, { type: 'init' })).toEqual(expectedState); + }); + }; + + describe(`without meta reducers`, () => { + const metaReducers: any[] = []; + describe( + `with initial state`, + runWithExpectations(metaReducers, initialState, initialState) + ); + describe( + `without initial state`, + runWithExpectations(metaReducers, undefined, { fruit: 'banana' }) + ); + }); + + describe(`with meta reducers`, () => { + const noopMetaReducer = (r: any) => r; + const metaReducers: any[] = [noopMetaReducer]; + describe( + `with initial state`, + runWithExpectations(metaReducers, initialState, initialState) + ); + describe( + `without initial state`, + runWithExpectations(metaReducers, undefined, { fruit: 'banana' }) + ); + }); + }); }); diff --git a/modules/store/src/utils.ts b/modules/store/src/utils.ts index a8a30c7642..856a79b705 100644 --- a/modules/store/src/utils.ts +++ b/modules/store/src/utils.ts @@ -89,7 +89,7 @@ export function createReducerFactory( metaReducers?: ActionReducer[] ): ActionReducerFactory { if (Array.isArray(metaReducers) && metaReducers.length > 0) { - return compose.apply(null, [...metaReducers, reducerFactory]); + return compose(...metaReducers)(reducerFactory) as any; } return reducerFactory; From b4577f3132ced00ae2f7d29aaaf6946b8ebd3513 Mon Sep 17 00:00:00 2001 From: Reko Jokelainen Date: Fri, 11 Aug 2017 08:26:30 +0300 Subject: [PATCH 2/2] fix: createReducerFactory double typing --- modules/store/src/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/store/src/utils.ts b/modules/store/src/utils.ts index 856a79b705..d1812a355c 100644 --- a/modules/store/src/utils.ts +++ b/modules/store/src/utils.ts @@ -89,7 +89,10 @@ export function createReducerFactory( metaReducers?: ActionReducer[] ): ActionReducerFactory { if (Array.isArray(metaReducers) && metaReducers.length > 0) { - return compose(...metaReducers)(reducerFactory) as any; + return compose(...metaReducers)(reducerFactory) as ActionReducerFactory< + any, + any + >; } return reducerFactory;