Skip to content

Commit ab56aac

Browse files
TeoTNbrandonroberts
authored andcommitted
feat(store): add testing package (#1027)
Introduces `@ngrx/store/testing` that provides a mock store for using in test setup Closes #915 ```ts import { Store } from '@ngrx/store'; import { provideMockStore, MockStore } from '@ngrx/store/testing'; import { take } from 'rxjs/operators'; describe('Mock Store', () => { let mockStore: MockStore<{ counter1: number, counter2: number }>; beforeEach(() => { const initialState = { counter1: 0, counter2: 1 }; TestBed.configureTestingModule({ providers: [provideMockStore({ initialState })], }); mockStore = TestBed.get(Store); }); it('should set the new state', () => { mockStore.setState({ counter1: 1, counter2: 2 }); mockStore.pipe(take(1)).subscribe(state => { expect(state.counter1).toBe(1); }); }); }); ```
1 parent d9de463 commit ab56aac

File tree

12 files changed

+190
-1
lines changed

12 files changed

+190
-1
lines changed

modules/store/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ng_package(
1616
name = "npm_package",
1717
srcs = glob(["**/*.externs.js"]) + [
1818
"package.json",
19+
"//modules/store/testing:package.json",
1920
],
2021
entry_point = "modules/store/index.js",
2122
packages = [
@@ -25,5 +26,6 @@ ng_package(
2526
],
2627
deps = [
2728
":store",
29+
"//modules/store/testing",
2830
],
2931
)

modules/store/spec/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ts_test_library(
1010
),
1111
deps = [
1212
"//modules/store",
13+
"//modules/store/testing",
1314
"@rxjs",
1415
"@rxjs//operators",
1516
],

modules/store/spec/store.spec.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
} from './fixtures/counter';
2020
import Spy = jasmine.Spy;
2121
import any = jasmine.any;
22-
import { take } from 'rxjs/operators';
22+
import { skip, take } from 'rxjs/operators';
23+
import { MockStore, provideMockStore } from '../testing';
2324

2425
interface TestAppSchema {
2526
counter1: number;
@@ -432,4 +433,42 @@ describe('ngRx Store', () => {
432433
};
433434
}
434435
});
436+
437+
describe('Mock Store', () => {
438+
let mockStore: MockStore<TestAppSchema>;
439+
440+
beforeEach(() => {
441+
const initialState = { counter1: 0, counter2: 1 };
442+
443+
TestBed.configureTestingModule({
444+
providers: [provideMockStore({ initialState })],
445+
});
446+
447+
mockStore = TestBed.get(Store);
448+
});
449+
450+
it('should set the initial state to a mocked one', (done: DoneFn) => {
451+
const fixedState = {
452+
counter1: 17,
453+
counter2: 11,
454+
counter3: 25,
455+
};
456+
mockStore.setState(fixedState);
457+
mockStore.pipe(take(1)).subscribe({
458+
next(val) {
459+
expect(val).toEqual(fixedState);
460+
},
461+
error: done.fail,
462+
complete: done,
463+
});
464+
});
465+
466+
it('should allow tracing dispatched actions', () => {
467+
const action = { type: INCREMENT };
468+
mockStore.scannedActions$
469+
.pipe(skip(1))
470+
.subscribe(scannedAction => expect(scannedAction).toEqual(action));
471+
mockStore.dispatch(action);
472+
});
473+
});
435474
});

modules/store/testing/BUILD

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
exports_files(["package.json"])
4+
5+
load("//tools:defaults.bzl", "ng_module")
6+
7+
ng_module(
8+
name = "testing",
9+
srcs = glob([
10+
"*.ts",
11+
"src/**/*.ts",
12+
]),
13+
module_name = "@ngrx/store/testing",
14+
visibility = ["//visibility:public"],
15+
deps = [
16+
"//modules/store",
17+
"@rxjs",
18+
],
19+
)

modules/store/testing/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './src/testing';

modules/store/testing/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "@ngrx/store/testing",
3+
"typings": "./testing.d.ts",
4+
"main": "../bundles/core-testing.umd.js",
5+
"module": "../fesm5/testing.js",
6+
"es2015": "../fesm2015/testing.js",
7+
"esm5": "../esm5/testing/testing.js",
8+
"esm2015": "../esm2015/testing/testing.js",
9+
"fesm5": "../fesm5/testing.js",
10+
"fesm2015": "../fesm2015/testing.js"
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default {
2+
entry: './dist/store/@ngrx/store/testing.es5.js',
3+
dest: './dist/store/bundles/store-testing.umd.js',
4+
format: 'umd',
5+
exports: 'named',
6+
moduleName: 'ngrx.store.testing',
7+
globals: {
8+
'@angular/core': 'ng.core',
9+
'@ngrx/store': 'ngrx.store',
10+
'rxjs': 'Rx',
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Injectable } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
3+
import { ActionReducer } from '@ngrx/store';
4+
5+
@Injectable()
6+
export class MockReducerManager extends BehaviorSubject<
7+
ActionReducer<any, any>
8+
> {
9+
constructor() {
10+
super(() => undefined);
11+
}
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Injectable } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
3+
4+
@Injectable()
5+
export class MockState<T extends {}> extends BehaviorSubject<T> {
6+
constructor() {
7+
super(<T>{});
8+
}
9+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Inject, Injectable } from '@angular/core';
2+
import { Observable, BehaviorSubject } from 'rxjs';
3+
import {
4+
Action,
5+
ActionsSubject,
6+
INITIAL_STATE,
7+
ReducerManager,
8+
Store,
9+
} from '@ngrx/store';
10+
import { MockState } from './mock_state';
11+
12+
@Injectable()
13+
export class MockStore<T> extends Store<T> {
14+
public scannedActions$: Observable<Action>;
15+
16+
constructor(
17+
private state$: MockState<T>,
18+
actionsObserver: ActionsSubject,
19+
reducerManager: ReducerManager,
20+
@Inject(INITIAL_STATE) private initialState: T
21+
) {
22+
super(state$, actionsObserver, reducerManager);
23+
this.state$.next(this.initialState);
24+
this.scannedActions$ = actionsObserver.asObservable();
25+
}
26+
27+
setState(nextState: T): void {
28+
this.state$.next(nextState);
29+
}
30+
31+
addReducer() {
32+
/* noop */
33+
}
34+
35+
removeReducer() {
36+
/* noop */
37+
}
38+
}

0 commit comments

Comments
 (0)