Skip to content

Commit

Permalink
fix(Effects): Ensure Store modules are loaded eagerly (#658)
Browse files Browse the repository at this point in the history
Closes #642
  • Loading branch information
brandonroberts authored and MikeRyanDev committed Dec 18, 2017
1 parent cb84a4d commit 0a3398d
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 44 deletions.
145 changes: 145 additions & 0 deletions modules/effects/spec/effects_feature_module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { TestBed } from '@angular/core/testing';
import { NgModule, Injectable } from '@angular/core';
import {
StoreModule,
Store,
Action,
createFeatureSelector,
createSelector,
select,
} from '@ngrx/store';
import { tap, withLatestFrom, map, mergeMap, filter } from 'rxjs/operators';
import { Observable } from 'rxjs/Observable';
import { cold } from 'jasmine-marbles';
import { EffectSources } from '../src/effect_sources';
import { FEATURE_EFFECTS } from '../src/tokens';
import { EffectsFeatureModule } from '../src/effects_feature_module';
import { EffectsRootModule } from '../src/effects_root_module';
import { EffectsModule, Effect, Actions, ofType } from '../';

describe('Effects Feature Module', () => {
describe('when registered', () => {
const sourceA = 'sourceA';
const sourceB = 'sourceB';
const sourceC = 'sourceC';
const effectSourceGroups = [[sourceA], [sourceB], [sourceC]];
let mockEffectSources: { addEffects: jasmine.Spy };

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: EffectsRootModule,
useValue: {
addEffects: jasmine.createSpy('addEffects'),
},
},
{
provide: FEATURE_EFFECTS,
useValue: effectSourceGroups,
},
EffectsFeatureModule,
],
});

mockEffectSources = TestBed.get(EffectsRootModule);
});

it('should add all effects when instantiated', () => {
TestBed.get(EffectsFeatureModule);

expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceA);
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceB);
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceC);
});
});

describe('when registered in a different NgModule from the feature state', () => {
let effects: FeatureEffects;
let actions$: Observable<any>;
let store: Store<any>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppModule],
});

effects = TestBed.get(FeatureEffects);
store = TestBed.get(Store);
});

it('should have the feature state defined to select from the effect', (
done: any
) => {
const action = { type: 'INCREMENT' };
const result = { type: 'INCREASE' };

effects.effectWithStore.subscribe(res => {
expect(res).toEqual(result);
});

store.dispatch(action);

store.pipe(select(getDataState)).subscribe(res => {
expect(res).toBe(110);
done();
});
});
});
});

const FEATURE_KEY = 'feature';

interface State {
FEATURE_KEY: DataState;
}

interface DataState {
data: number;
}

const initialState: DataState = {
data: 100,
};

function reducer(state: DataState = initialState, action: Action) {
switch (action.type) {
case 'INCREASE':
return {
data: state.data + 10,
};
}
return state;
}

const getFeatureState = createFeatureSelector<DataState>(FEATURE_KEY);

const getDataState = createSelector(getFeatureState, state => state.data);

@Injectable()
class FeatureEffects {
constructor(private actions: Actions, private store: Store<State>) {}

@Effect()
effectWithStore = this.actions
.ofType('INCREMENT')
.pipe(
withLatestFrom(this.store.select(getDataState)),
map(([action, state]) => ({ type: 'INCREASE' }))
);
}

@NgModule({
imports: [EffectsModule.forFeature([FeatureEffects])],
})
class FeatureEffectsModule {}

@NgModule({
imports: [FeatureEffectsModule, StoreModule.forFeature(FEATURE_KEY, reducer)],
})
class FeatureModule {}

@NgModule({
imports: [StoreModule.forRoot({}), EffectsModule.forRoot([]), FeatureModule],
})
class AppModule {}
40 changes: 0 additions & 40 deletions modules/effects/spec/effects_feature_module.ts

This file was deleted.

5 changes: 3 additions & 2 deletions modules/effects/src/effects_feature_module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NgModule, Inject, Optional } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreRootModule, StoreFeatureModule } from '@ngrx/store';
import { EffectsRootModule } from './effects_root_module';
import { FEATURE_EFFECTS } from './tokens';

Expand All @@ -8,7 +8,8 @@ export class EffectsFeatureModule {
constructor(
private root: EffectsRootModule,
@Inject(FEATURE_EFFECTS) effectSourceGroups: any[][],
@Optional() storeModule: StoreModule
@Optional() storeRootModule: StoreRootModule,
@Optional() storeFeatureModule: StoreFeatureModule
) {
effectSourceGroups.forEach(group =>
group.forEach(effectSourceInstance =>
Expand Down
10 changes: 8 additions & 2 deletions modules/effects/src/effects_root_module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { NgModule, Inject, Optional } from '@angular/core';
import { StoreModule, Store } from '@ngrx/store';
import {
StoreModule,
Store,
StoreRootModule,
StoreFeatureModule,
} from '@ngrx/store';
import { EffectsRunner } from './effects_runner';
import { EffectSources } from './effect_sources';
import { ROOT_EFFECTS } from './tokens';
Expand All @@ -13,7 +18,8 @@ export class EffectsRootModule {
runner: EffectsRunner,
store: Store<any>,
@Inject(ROOT_EFFECTS) rootEffects: any[],
@Optional() storeModule: StoreModule
@Optional() storeRootModule: StoreRootModule,
@Optional() storeFeatureModule: StoreFeatureModule
) {
runner.start();

Expand Down

0 comments on commit 0a3398d

Please sign in to comment.