Skip to content

Commit 0a3398d

Browse files
brandonrobertsMikeRyanDev
authored andcommitted
fix(Effects): Ensure Store modules are loaded eagerly (#658)
Closes #642
1 parent cb84a4d commit 0a3398d

File tree

4 files changed

+156
-44
lines changed

4 files changed

+156
-44
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { TestBed } from '@angular/core/testing';
2+
import { NgModule, Injectable } from '@angular/core';
3+
import {
4+
StoreModule,
5+
Store,
6+
Action,
7+
createFeatureSelector,
8+
createSelector,
9+
select,
10+
} from '@ngrx/store';
11+
import { tap, withLatestFrom, map, mergeMap, filter } from 'rxjs/operators';
12+
import { Observable } from 'rxjs/Observable';
13+
import { cold } from 'jasmine-marbles';
14+
import { EffectSources } from '../src/effect_sources';
15+
import { FEATURE_EFFECTS } from '../src/tokens';
16+
import { EffectsFeatureModule } from '../src/effects_feature_module';
17+
import { EffectsRootModule } from '../src/effects_root_module';
18+
import { EffectsModule, Effect, Actions, ofType } from '../';
19+
20+
describe('Effects Feature Module', () => {
21+
describe('when registered', () => {
22+
const sourceA = 'sourceA';
23+
const sourceB = 'sourceB';
24+
const sourceC = 'sourceC';
25+
const effectSourceGroups = [[sourceA], [sourceB], [sourceC]];
26+
let mockEffectSources: { addEffects: jasmine.Spy };
27+
28+
beforeEach(() => {
29+
TestBed.configureTestingModule({
30+
providers: [
31+
{
32+
provide: EffectsRootModule,
33+
useValue: {
34+
addEffects: jasmine.createSpy('addEffects'),
35+
},
36+
},
37+
{
38+
provide: FEATURE_EFFECTS,
39+
useValue: effectSourceGroups,
40+
},
41+
EffectsFeatureModule,
42+
],
43+
});
44+
45+
mockEffectSources = TestBed.get(EffectsRootModule);
46+
});
47+
48+
it('should add all effects when instantiated', () => {
49+
TestBed.get(EffectsFeatureModule);
50+
51+
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceA);
52+
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceB);
53+
expect(mockEffectSources.addEffects).toHaveBeenCalledWith(sourceC);
54+
});
55+
});
56+
57+
describe('when registered in a different NgModule from the feature state', () => {
58+
let effects: FeatureEffects;
59+
let actions$: Observable<any>;
60+
let store: Store<any>;
61+
62+
beforeEach(() => {
63+
TestBed.configureTestingModule({
64+
imports: [AppModule],
65+
});
66+
67+
effects = TestBed.get(FeatureEffects);
68+
store = TestBed.get(Store);
69+
});
70+
71+
it('should have the feature state defined to select from the effect', (
72+
done: any
73+
) => {
74+
const action = { type: 'INCREMENT' };
75+
const result = { type: 'INCREASE' };
76+
77+
effects.effectWithStore.subscribe(res => {
78+
expect(res).toEqual(result);
79+
});
80+
81+
store.dispatch(action);
82+
83+
store.pipe(select(getDataState)).subscribe(res => {
84+
expect(res).toBe(110);
85+
done();
86+
});
87+
});
88+
});
89+
});
90+
91+
const FEATURE_KEY = 'feature';
92+
93+
interface State {
94+
FEATURE_KEY: DataState;
95+
}
96+
97+
interface DataState {
98+
data: number;
99+
}
100+
101+
const initialState: DataState = {
102+
data: 100,
103+
};
104+
105+
function reducer(state: DataState = initialState, action: Action) {
106+
switch (action.type) {
107+
case 'INCREASE':
108+
return {
109+
data: state.data + 10,
110+
};
111+
}
112+
return state;
113+
}
114+
115+
const getFeatureState = createFeatureSelector<DataState>(FEATURE_KEY);
116+
117+
const getDataState = createSelector(getFeatureState, state => state.data);
118+
119+
@Injectable()
120+
class FeatureEffects {
121+
constructor(private actions: Actions, private store: Store<State>) {}
122+
123+
@Effect()
124+
effectWithStore = this.actions
125+
.ofType('INCREMENT')
126+
.pipe(
127+
withLatestFrom(this.store.select(getDataState)),
128+
map(([action, state]) => ({ type: 'INCREASE' }))
129+
);
130+
}
131+
132+
@NgModule({
133+
imports: [EffectsModule.forFeature([FeatureEffects])],
134+
})
135+
class FeatureEffectsModule {}
136+
137+
@NgModule({
138+
imports: [FeatureEffectsModule, StoreModule.forFeature(FEATURE_KEY, reducer)],
139+
})
140+
class FeatureModule {}
141+
142+
@NgModule({
143+
imports: [StoreModule.forRoot({}), EffectsModule.forRoot([]), FeatureModule],
144+
})
145+
class AppModule {}

modules/effects/spec/effects_feature_module.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

modules/effects/src/effects_feature_module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NgModule, Inject, Optional } from '@angular/core';
2-
import { StoreModule } from '@ngrx/store';
2+
import { StoreRootModule, StoreFeatureModule } from '@ngrx/store';
33
import { EffectsRootModule } from './effects_root_module';
44
import { FEATURE_EFFECTS } from './tokens';
55

@@ -8,7 +8,8 @@ export class EffectsFeatureModule {
88
constructor(
99
private root: EffectsRootModule,
1010
@Inject(FEATURE_EFFECTS) effectSourceGroups: any[][],
11-
@Optional() storeModule: StoreModule
11+
@Optional() storeRootModule: StoreRootModule,
12+
@Optional() storeFeatureModule: StoreFeatureModule
1213
) {
1314
effectSourceGroups.forEach(group =>
1415
group.forEach(effectSourceInstance =>

modules/effects/src/effects_root_module.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { NgModule, Inject, Optional } from '@angular/core';
2-
import { StoreModule, Store } from '@ngrx/store';
2+
import {
3+
StoreModule,
4+
Store,
5+
StoreRootModule,
6+
StoreFeatureModule,
7+
} from '@ngrx/store';
38
import { EffectsRunner } from './effects_runner';
49
import { EffectSources } from './effect_sources';
510
import { ROOT_EFFECTS } from './tokens';
@@ -13,7 +18,8 @@ export class EffectsRootModule {
1318
runner: EffectsRunner,
1419
store: Store<any>,
1520
@Inject(ROOT_EFFECTS) rootEffects: any[],
16-
@Optional() storeModule: StoreModule
21+
@Optional() storeRootModule: StoreRootModule,
22+
@Optional() storeFeatureModule: StoreFeatureModule
1723
) {
1824
runner.start();
1925

0 commit comments

Comments
 (0)