Skip to content

Commit f22d2c3

Browse files
brandonrobertsMikeRyanDev
authored andcommitted
chore(docs): Updated migration guide for testing effects (#78)
1 parent c9d6a45 commit f22d2c3

File tree

7 files changed

+139
-46
lines changed

7 files changed

+139
-46
lines changed

MIGRATION.md

+81
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ export class AppModule {}
8282

8383
## @ngrx/effects
8484

85+
### Registering Effects
86+
8587
BEFORE:
8688

8789
`app.module.ts`
@@ -125,6 +127,85 @@ export class AppModule { }
125127
export class FeatureModule { }
126128
```
127129

130+
### Testing Effects
131+
132+
BEFORE:
133+
```ts
134+
import { EffectsTestingModule, EffectsRunner } from '@ngrx/effects/testing';
135+
import { MyEffects } from './my-effects';
136+
137+
describe('My Effects', () => {
138+
let effects: MyEffects;
139+
let runner: EffectsRunner;
140+
beforeEach(() => {
141+
TestBed.configureTestingModule({
142+
imports: [
143+
EffectsTestingModule
144+
],
145+
providers: [
146+
MyEffects,
147+
// other providers
148+
],
149+
});
150+
151+
effects = TestBed.get(MyEffects);
152+
runner = TestBed.get(EffectsRunner);
153+
});
154+
155+
it('should work', () => {
156+
runner.queue(SomeAction);
157+
158+
effects.someSource$.subscribe(result => {
159+
expect(result).toBe(AnotherAction);
160+
});
161+
});
162+
});
163+
```
164+
165+
AFTER:
166+
```ts
167+
import { TestBed } from '@angular/core/testing';
168+
import { provideMockActions } from '@ngrx/effects/testing';
169+
import { hot, cold } from 'jasmine-marbles';
170+
import { MyEffects } from './my-effects';
171+
import { ReplaySubject } from 'rxjs/ReplaySubject';
172+
173+
describe('My Effects', () => {
174+
let effects: MyEffects;
175+
let actions: Observable<any>;
176+
177+
beforeEach(() => {
178+
TestBed.configureTestingModule({
179+
providers: [
180+
MyEffects,
181+
provideMockActions(() => actions),
182+
// other providers
183+
],
184+
});
185+
186+
effects = TestBed.get(MyEffects);
187+
});
188+
189+
it('should work', () => {
190+
actions = hot('--a-', { a: SomeAction, ... });
191+
192+
const expected = cold('--b', { b: AnotherAction });
193+
194+
expect(effects.someSource$).toBeObservable(expected);
195+
});
196+
197+
it('should work also', () => {
198+
actions = new ReplaySubject(1);
199+
200+
actions.next(SomeAction);
201+
202+
effects.someSource$.subscribe(result => {
203+
expect(result).toBe(AnotherAction);
204+
});
205+
});
206+
});
207+
```
208+
128209
## @ngrx/router-store
129210

130211
BEFORE:

docs/effects/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,4 @@ export class AdminModule {}
104104
- [Filtering Actions](./api.md#oftype)
105105
- [Non-dispatching effects](./api.md#non-dispatching-effects)
106106
- [Utilities](./api.md#utilities)
107+
- [Testing](./testing.md)

docs/effects/testing.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Testing
2+
3+
## @ngrx/effects/testing
4+
5+
### provideMockActions
6+
Provides a mock test provider of the `Actions` Observable for testing effects. This works well with writing
7+
marble tests and tests using the `subscribe` method on an Observable. The mock Actions will deliver a new Observable
8+
to subscribe to for each test.
9+
10+
Usage:
11+
```ts
12+
import { TestBed } from '@angular/core/testing';
13+
import { provideMockActions } from '@ngrx/effects/testing';
14+
import { ReplaySubject } from 'rxjs/ReplaySubject';
15+
import { hot, cold } from 'jasmine-marbles';
16+
import { MyEffects } from './my-effects';
17+
18+
describe('My Effects', () => {
19+
let effects: MyEffects;
20+
let actions: Observable<any>;
21+
22+
beforeEach(() => {
23+
TestBed.configureTestingModule({
24+
providers: [
25+
MyEffects,
26+
provideMockActions(() => actions),
27+
// other providers
28+
],
29+
});
30+
31+
effects = TestBed.get(MyEffects);
32+
});
33+
34+
it('should work', () => {
35+
actions = hot('--a-', { a: SomeAction });
36+
37+
const expected = cold('--b', { b: AnotherAction });
38+
39+
expect(effects.someSource$).toBeObservable(expected);
40+
});
41+
42+
it('should work also', () => {
43+
actions = new ReplaySubject(1);
44+
45+
actions.next(SomeAction);
46+
47+
effects.someSource$.subscribe(result => {
48+
expect(result).toEqual(AnotherAction);
49+
});
50+
});
51+
});
52+
```

docs/store/api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Initial State
44

5-
Configure initial state when providing Store. `config.initialState` can be either the actual state, or a function that returns the initial state:
5+
Configure initial state when providing Store. `initialState` can be either the actual state, or a function that returns the initial state:
66

77
```ts
88
import { StoreModule } from '@ngrx/store';

example-app/app/app.module.ts

+2-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { CoreModule } from './core/core.module';
1616
import { AuthModule } from './auth/auth.module';
1717

1818
import { routes } from './routes';
19-
import { reducers, developmentReducerFactory } from './reducers';
19+
import { reducers } from './reducers';
2020
import { schema } from './db';
2121

2222
import { AppComponent } from './core/containers/app';
@@ -37,11 +37,7 @@ import { environment } from '../environments/environment';
3737
* meta-reducer. This returns all providers for an @ngrx/store
3838
* based application.
3939
*/
40-
StoreModule.forRoot(reducers, {
41-
reducerFactory: !environment.production
42-
? developmentReducerFactory
43-
: undefined,
44-
}),
40+
StoreModule.forRoot(reducers),
4541

4642
/**
4743
* @ngrx/router-store keeps router state up-to-date in the store.

example-app/app/books/books.module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ import { reducers } from './reducers';
4141
StoreModule.forFeature('books', reducers),
4242

4343
/**
44-
* Effects.forFeature is used to regiser effects
44+
* Effects.forFeature is used to register effects
4545
* from feature modules. Effects can be loaded
4646
* eagerly or lazily and will be started immediately.
47-
*
47+
*
4848
* All Effects will only be instantiated once regardless of
4949
* whether they are registered once or multiple times.
5050
*/

example-app/app/reducers/index.ts

-37
Original file line numberDiff line numberDiff line change
@@ -37,43 +37,6 @@ export const reducers: ActionReducerMap<State> = {
3737
layout: fromLayout.reducer,
3838
};
3939

40-
// console.log all actions
41-
export function logger(reducer: ActionReducer<State>) {
42-
return function(state: State, action: any) {
43-
console.log('state', state);
44-
console.log('action', action);
45-
46-
return reducer(state, action);
47-
};
48-
}
49-
50-
/**
51-
* The compose function is one of our most handy tools. In basic terms, you give
52-
* it any number of functions and it returns a function. This new function
53-
* takes a value and chains it through every composed function, returning
54-
* the output.
55-
*
56-
* More: https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch5.html
57-
*/
58-
59-
/**
60-
* combineReducers is another useful metareducer that takes a map of reducer
61-
* functions and creates a new reducer that gathers the values
62-
* of each reducer and stores them using the reducer's key. Think of it
63-
* almost like a database, where every reducer is a table in the db.
64-
*
65-
* More: https://egghead.io/lessons/javascript-redux-implementing-combinereducers-from-scratch
66-
*/
67-
68-
/**
69-
* By default, @ngrx/store uses combineReducers with the reducer map to compose the root meta-reducer.
70-
* To add more meta-reducers, provide a custom reducer factory.
71-
*/
72-
export const developmentReducerFactory: ActionReducerFactory<
73-
State,
74-
Action
75-
> = compose(logger, combineReducers);
76-
7740
/**
7841
* Layout Reducers
7942
*/

0 commit comments

Comments
 (0)