From e009b2f5b29f60183b34044d85f60d71ead9e1c0 Mon Sep 17 00:00:00 2001 From: ijz953 Date: Thu, 2 May 2019 18:20:53 -0400 Subject: [PATCH 1/2] feat(store): feat(store): add option to mock selectors in MockStoreConfig --- modules/store/spec/store.spec.ts | 47 +++++++++++++++++-- modules/store/src/index.ts | 1 + modules/store/src/tokens.ts | 3 ++ modules/store/testing/src/mock_selector.ts | 9 ++++ modules/store/testing/src/mock_store.ts | 15 +++++- modules/store/testing/src/testing.ts | 5 ++ .../containers/login-page.component.spec.ts | 7 ++- .../collection-page.component.spec.ts | 8 ++-- .../find-book-page.component.spec.ts | 16 ++++--- 9 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 modules/store/testing/src/mock_selector.ts diff --git a/modules/store/spec/store.spec.ts b/modules/store/spec/store.spec.ts index 10b7d97326..44a84cf05d 100644 --- a/modules/store/spec/store.spec.ts +++ b/modules/store/spec/store.spec.ts @@ -449,11 +449,24 @@ describe('ngRx Store', () => { describe('Mock Store', () => { let mockStore: MockStore; - const initialState = { counter1: 0, counter2: 1 }; + const initialState = { counter1: 0, counter2: 1, counter4: 3 }; + const stringSelector = 'counter4'; + const memoizedSelector = createSelector( + () => initialState, + state => state.counter4 + ); beforeEach(() => { TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState })], + providers: [ + provideMockStore({ + initialState, + selectors: [ + { selector: stringSelector, value: 87 }, + { selector: memoizedSelector, value: 98 }, + ], + }), + ], }); mockStore = TestBed.get(Store); @@ -483,7 +496,31 @@ describe('ngRx Store', () => { mockStore.dispatch(action); }); - it('should allow mocking of store.select with string selector', () => { + it('should allow mocking of store.select with string selector using provideMockStore', () => { + const expectedValue = 87; + + mockStore + .select(stringSelector) + .subscribe(result => expect(result).toBe(expectedValue)); + }); + + it('should allow mocking of store.select with a memoized selector using provideMockStore', () => { + const expectedValue = 98; + + mockStore + .select(memoizedSelector) + .subscribe(result => expect(result).toBe(expectedValue)); + }); + + it('should allow mocking of store.pipe(select()) with a memoized selector using provideMockStore', () => { + const expectedValue = 98; + + mockStore + .pipe(select(memoizedSelector)) + .subscribe(result => expect(result).toBe(expectedValue)); + }); + + it('should allow mocking of store.select with string selector using overrideSelector', () => { const mockValue = 5; mockStore.overrideSelector('counter1', mockValue); @@ -493,7 +530,7 @@ describe('ngRx Store', () => { .subscribe(result => expect(result).toBe(mockValue)); }); - it('should allow mocking of store.select with a memoized selector', () => { + it('should allow mocking of store.select with a memoized selector using overrideSelector', () => { const mockValue = 5; const selector = createSelector( () => initialState, @@ -507,7 +544,7 @@ describe('ngRx Store', () => { .subscribe(result => expect(result).toBe(mockValue)); }); - it('should allow mocking of store.pipe(select()) with a memoized selector', () => { + it('should allow mocking of store.pipe(select()) with a memoized selector using overrideSelector', () => { const mockValue = 5; const selector = createSelector( () => initialState, diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index 5a85ec167b..26266059c9 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -41,6 +41,7 @@ export { META_REDUCERS, FEATURE_REDUCERS, USER_PROVIDED_META_REDUCERS, + MOCK_SELECTORS, } from './tokens'; export { StoreModule, diff --git a/modules/store/src/tokens.ts b/modules/store/src/tokens.ts index 64097d5ff6..675294b503 100644 --- a/modules/store/src/tokens.ts +++ b/modules/store/src/tokens.ts @@ -5,6 +5,9 @@ export const _INITIAL_STATE = new InjectionToken( '@ngrx/store Internal Initial State' ); export const INITIAL_STATE = new InjectionToken('@ngrx/store Initial State'); +export const MOCK_SELECTORS = new InjectionToken( + '@ngrx/store Initial Selector Values' +); export const REDUCER_FACTORY = new InjectionToken( '@ngrx/store Reducer Factory' ); diff --git a/modules/store/testing/src/mock_selector.ts b/modules/store/testing/src/mock_selector.ts new file mode 100644 index 0000000000..a2aa469312 --- /dev/null +++ b/modules/store/testing/src/mock_selector.ts @@ -0,0 +1,9 @@ +import { MemoizedSelector, MemoizedSelectorWithProps } from '@ngrx/store'; + +export interface MockSelector { + selector: + | string + | MemoizedSelector + | MemoizedSelectorWithProps; + value: any; +} diff --git a/modules/store/testing/src/mock_store.ts b/modules/store/testing/src/mock_store.ts index 506d57755e..1f4f7ff0c2 100644 --- a/modules/store/testing/src/mock_store.ts +++ b/modules/store/testing/src/mock_store.ts @@ -4,6 +4,7 @@ import { Action, ActionsSubject, INITIAL_STATE, + MOCK_SELECTORS, ReducerManager, Store, createSelector, @@ -11,6 +12,7 @@ import { MemoizedSelector, } from '@ngrx/store'; import { MockState } from './mock_state'; +import { MockSelector } from './mock_selector'; @Injectable() export class MockStore extends Store { @@ -27,12 +29,23 @@ export class MockStore extends Store { private state$: MockState, actionsObserver: ActionsSubject, reducerManager: ReducerManager, - @Inject(INITIAL_STATE) private initialState: T + @Inject(INITIAL_STATE) private initialState: T, + @Inject(MOCK_SELECTORS) mockSelectors?: MockSelector[] ) { super(state$, actionsObserver, reducerManager); this.resetSelectors(); this.state$.next(this.initialState); this.scannedActions$ = actionsObserver.asObservable(); + if (mockSelectors) { + mockSelectors.forEach(mockSelector => { + const selector = mockSelector.selector; + if (typeof selector === 'string') { + this.overrideSelector(selector, mockSelector.value); + } else { + this.overrideSelector(selector, mockSelector.value); + } + }); + } } setState(nextState: T): void { diff --git a/modules/store/testing/src/testing.ts b/modules/store/testing/src/testing.ts index a31f4eb4b9..660f1e1e7c 100644 --- a/modules/store/testing/src/testing.ts +++ b/modules/store/testing/src/testing.ts @@ -3,15 +3,18 @@ import { MockState } from './mock_state'; import { ActionsSubject, INITIAL_STATE, + MOCK_SELECTORS, ReducerManager, StateObservable, Store, } from '@ngrx/store'; import { MockStore } from './mock_store'; import { MockReducerManager } from './mock_reducer_manager'; +import { MockSelector } from './mock_selector'; export interface MockStoreConfig { initialState?: T; + selectors?: MockSelector[]; } export function provideMockStore( @@ -21,6 +24,7 @@ export function provideMockStore( ActionsSubject, MockState, { provide: INITIAL_STATE, useValue: config.initialState }, + { provide: MOCK_SELECTORS, useValue: config.selectors }, { provide: StateObservable, useClass: MockState }, { provide: ReducerManager, useClass: MockReducerManager }, { provide: Store, useClass: MockStore }, @@ -30,3 +34,4 @@ export function provideMockStore( export { MockReducerManager } from './mock_reducer_manager'; export { MockState } from './mock_state'; export { MockStore } from './mock_store'; +export { MockSelector } from './mock_selector'; diff --git a/projects/example-app/src/app/auth/containers/login-page.component.spec.ts b/projects/example-app/src/app/auth/containers/login-page.component.spec.ts index 6dcb528735..b77965b95d 100644 --- a/projects/example-app/src/app/auth/containers/login-page.component.spec.ts +++ b/projects/example-app/src/app/auth/containers/login-page.component.spec.ts @@ -23,13 +23,16 @@ describe('Login Page', () => { ReactiveFormsModule, ], declarations: [LoginPageComponent, LoginFormComponent], - providers: [provideMockStore()], + providers: [ + provideMockStore({ + selectors: [{ selector: fromAuth.getLoginPagePending, value: false }], + }), + ], }); fixture = TestBed.createComponent(LoginPageComponent); instance = fixture.componentInstance; store = TestBed.get(Store); - store.overrideSelector(fromAuth.getLoginPagePending, false); spyOn(store, 'dispatch'); }); diff --git a/projects/example-app/src/app/books/containers/collection-page.component.spec.ts b/projects/example-app/src/app/books/containers/collection-page.component.spec.ts index 3057aad4cd..f110737588 100644 --- a/projects/example-app/src/app/books/containers/collection-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/collection-page.component.spec.ts @@ -34,7 +34,11 @@ describe('Collection Page', () => { AddCommasPipe, EllipsisPipe, ], - providers: [provideMockStore()], + providers: [ + provideMockStore({ + selectors: [{ selector: fromBooks.getBookCollection, value: [] }], + }), + ], }); fixture = TestBed.createComponent(CollectionPageComponent); @@ -45,8 +49,6 @@ describe('Collection Page', () => { }); it('should compile', () => { - store.overrideSelector(fromBooks.getBookCollection, []); - fixture.detectChanges(); expect(fixture).toMatchSnapshot(); diff --git a/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts b/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts index cf54889e54..6590e48330 100644 --- a/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts +++ b/projects/example-app/src/app/books/containers/find-book-page.component.spec.ts @@ -44,7 +44,16 @@ describe('Find Book Page', () => { AddCommasPipe, EllipsisPipe, ], - providers: [provideMockStore()], + providers: [ + provideMockStore({ + selectors: [ + { selector: fromBooks.getSearchQuery, value: '' }, + { selector: fromBooks.getSearchResults, value: [] }, + { selector: fromBooks.getSearchLoading, value: false }, + { selector: fromBooks.getSearchError, value: '' }, + ], + }), + ], }); fixture = TestBed.createComponent(FindBookPageComponent); @@ -52,11 +61,6 @@ describe('Find Book Page', () => { store = TestBed.get(Store); spyOn(store, 'dispatch'); - - store.overrideSelector(fromBooks.getSearchQuery, ''); - store.overrideSelector(fromBooks.getSearchResults, []); - store.overrideSelector(fromBooks.getSearchLoading, false); - store.overrideSelector(fromBooks.getSearchError, ''); }); it('should compile', () => { From ed7cc490d2b852b9a71573e8d6c84c44cfb1aae9 Mon Sep 17 00:00:00 2001 From: ijz953 Date: Wed, 8 May 2019 14:34:33 -0400 Subject: [PATCH 2/2] feat(store): move mock selectors token to testing module --- modules/store/src/index.ts | 1 - modules/store/src/tokens.ts | 3 --- modules/store/testing/src/mock_store.ts | 2 +- modules/store/testing/src/testing.ts | 2 +- modules/store/testing/src/tokens.ts | 3 +++ 5 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 modules/store/testing/src/tokens.ts diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index 26266059c9..5a85ec167b 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -41,7 +41,6 @@ export { META_REDUCERS, FEATURE_REDUCERS, USER_PROVIDED_META_REDUCERS, - MOCK_SELECTORS, } from './tokens'; export { StoreModule, diff --git a/modules/store/src/tokens.ts b/modules/store/src/tokens.ts index 675294b503..64097d5ff6 100644 --- a/modules/store/src/tokens.ts +++ b/modules/store/src/tokens.ts @@ -5,9 +5,6 @@ export const _INITIAL_STATE = new InjectionToken( '@ngrx/store Internal Initial State' ); export const INITIAL_STATE = new InjectionToken('@ngrx/store Initial State'); -export const MOCK_SELECTORS = new InjectionToken( - '@ngrx/store Initial Selector Values' -); export const REDUCER_FACTORY = new InjectionToken( '@ngrx/store Reducer Factory' ); diff --git a/modules/store/testing/src/mock_store.ts b/modules/store/testing/src/mock_store.ts index 1f4f7ff0c2..2a04e4ccb8 100644 --- a/modules/store/testing/src/mock_store.ts +++ b/modules/store/testing/src/mock_store.ts @@ -4,7 +4,6 @@ import { Action, ActionsSubject, INITIAL_STATE, - MOCK_SELECTORS, ReducerManager, Store, createSelector, @@ -13,6 +12,7 @@ import { } from '@ngrx/store'; import { MockState } from './mock_state'; import { MockSelector } from './mock_selector'; +import { MOCK_SELECTORS } from './tokens'; @Injectable() export class MockStore extends Store { diff --git a/modules/store/testing/src/testing.ts b/modules/store/testing/src/testing.ts index 660f1e1e7c..a81c6bd30b 100644 --- a/modules/store/testing/src/testing.ts +++ b/modules/store/testing/src/testing.ts @@ -3,7 +3,6 @@ import { MockState } from './mock_state'; import { ActionsSubject, INITIAL_STATE, - MOCK_SELECTORS, ReducerManager, StateObservable, Store, @@ -11,6 +10,7 @@ import { import { MockStore } from './mock_store'; import { MockReducerManager } from './mock_reducer_manager'; import { MockSelector } from './mock_selector'; +import { MOCK_SELECTORS } from './tokens'; export interface MockStoreConfig { initialState?: T; diff --git a/modules/store/testing/src/tokens.ts b/modules/store/testing/src/tokens.ts new file mode 100644 index 0000000000..562b61b8b0 --- /dev/null +++ b/modules/store/testing/src/tokens.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const MOCK_SELECTORS = new InjectionToken('@ngrx/store Mock Selectors');