diff --git a/docs/effects/testing.md b/docs/effects/testing.md index a4e5aac190..a89fc0d77e 100644 --- a/docs/effects/testing.md +++ b/docs/effects/testing.md @@ -19,8 +19,7 @@ Usage: ```ts import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import { hot, cold } from 'jasmine-marbles'; +import { cold, hot } from 'jasmine-marbles'; import { Observable } from 'rxjs'; import { MyEffects } from './my-effects'; @@ -28,7 +27,7 @@ import * as MyActions from '../actions/my-actions'; describe('My Effects', () => { let effects: MyEffects; - let actions: Subject; + let actions: Observable>; beforeEach(() => { TestBed.configureTestingModule({ @@ -55,14 +54,44 @@ describe('My Effects', () => { expect(effects.someSource$).toBeObservable(expected); }); +}); +``` - it('should work also', () => { - actions = new ReplaySubject(1); +It is also possible to use `ReplaySubject` as an alternative for marble tests: + +```ts +import { TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { ReplaySubject } from 'rxjs'; + +import { MyEffects } from './my-effects'; +import * as MyActions from '../actions/my-actions'; + +describe('My Effects', () => { + let effects: MyEffects; + let actions: ReplaySubject<any>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + // any modules needed + ], + providers: [ + MyEffects, + provideMockActions(() => actions), + // other providers + ], + }); - actions.next(SomeAction); + effects = TestBed.get(MyEffects); + }); + + it('should work', () => { + actions = new ReplaySubject(1); + actions.next(new MyActions.ExampleAction()); effects.someSource$.subscribe(result => { - expect(result).toEqual(AnotherAction); + expect(result).toEqual(new MyActions.ExampleActionSuccess()); }); }); }); diff --git a/modules/effects/schematics-core/utility/project.ts b/modules/effects/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/effects/schematics-core/utility/project.ts +++ b/modules/effects/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/entity/schematics-core/utility/project.ts b/modules/entity/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/entity/schematics-core/utility/project.ts +++ b/modules/entity/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/router-store/schematics-core/utility/project.ts b/modules/router-store/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/router-store/schematics-core/utility/project.ts +++ b/modules/router-store/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/schematics-core/testing/create-workspace.ts b/modules/schematics-core/testing/create-workspace.ts index 0bebb4d576..83e563f48f 100644 --- a/modules/schematics-core/testing/create-workspace.ts +++ b/modules/schematics-core/testing/create-workspace.ts @@ -7,6 +7,7 @@ export const defaultWorkspaceOptions = { name: 'workspace', newProjectRoot: 'projects', version: '6.0.0', + defaultProject: 'bar', }; export const defaultAppOptions = { diff --git a/modules/schematics-core/utility/project.ts b/modules/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/schematics-core/utility/project.ts +++ b/modules/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/schematics/schematics-core/utility/project.ts b/modules/schematics/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/schematics/schematics-core/utility/project.ts +++ b/modules/schematics/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/schematics/src/store/index.spec.ts b/modules/schematics/src/store/index.spec.ts index f342a4c917..741ae04756 100644 --- a/modules/schematics/src/store/index.spec.ts +++ b/modules/schematics/src/store/index.spec.ts @@ -37,7 +37,9 @@ describe('Store Schematic', () => { const options = { ...defaultOptions }; const tree = schematicRunner.runSchematic('store', options, appTree); + const files = tree.files; + expect( files.indexOf(`${projectPath}/src/app/reducers/index.ts`) ).toBeGreaterThanOrEqual(0); @@ -56,11 +58,32 @@ describe('Store Schematic', () => { const tree = schematicRunner.runSchematic('store', options, appTree); const files = tree.files; + expect( files.indexOf(`${specifiedProjectPath}/src/lib/reducers/index.ts`) ).toBeGreaterThanOrEqual(0); }); + it('should create the initial store to defaultProject if project is not provided', () => { + const options = { + ...defaultOptions, + project: undefined, + }; + + const specifiedProjectPath = getTestProjectPath(defaultWorkspaceOptions, { + ...defaultAppOptions, + name: defaultWorkspaceOptions.defaultProject, + }); + + const tree = schematicRunner.runSchematic('store', options, appTree); + + const files = tree.files; + + expect( + files.indexOf(`${specifiedProjectPath}/src/app/reducers/index.ts`) + ).toBeGreaterThanOrEqual(0); + }); + it('should not be provided by default', () => { const options = { ...defaultOptions }; diff --git a/modules/store-devtools/schematics-core/utility/project.ts b/modules/store-devtools/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/store-devtools/schematics-core/utility/project.ts +++ b/modules/store-devtools/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/modules/store/schematics-core/utility/project.ts b/modules/store/schematics-core/utility/project.ts index 12b1e86c21..43145d20fd 100644 --- a/modules/store/schematics-core/utility/project.ts +++ b/modules/store/schematics-core/utility/project.ts @@ -13,7 +13,10 @@ export function getProject( const workspace = getWorkspace(host); if (!options.project) { - options.project = Object.keys(workspace.projects)[0]; + options.project = + workspace.defaultProject !== undefined + ? workspace.defaultProject + : Object.keys(workspace.projects)[0]; } return workspace.projects[options.project]; diff --git a/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap b/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap index c726290936..945329d0be 100644 --- a/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap +++ b/projects/example-app/src/app/books/containers/__snapshots__/selected-book-page.component.spec.ts.snap @@ -8,6 +8,7 @@ exports[`Selected Book Page should compile 1`] = ` > diff --git a/projects/example-app/src/app/books/reducers/index.ts b/projects/example-app/src/app/books/reducers/index.ts index 97e25c7178..73146eab03 100644 --- a/projects/example-app/src/app/books/reducers/index.ts +++ b/projects/example-app/src/app/books/reducers/index.ts @@ -156,6 +156,6 @@ export const isSelectedBookInCollection = createSelector( getCollectionBookIds, getSelectedBookId, (ids, selected) => { - return selected && ids.indexOf(selected) > -1; + return !!selected && ids.indexOf(selected) > -1; } ); diff --git a/projects/example-app/src/app/core/containers/app.component.ts b/projects/example-app/src/app/core/containers/app.component.ts index fa2acfd019..81bc56b81e 100644 --- a/projects/example-app/src/app/core/containers/app.component.ts +++ b/projects/example-app/src/app/core/containers/app.component.ts @@ -38,7 +38,7 @@ export class AppComponent { showSidenav$: Observable; loggedIn$: Observable; - constructor(private store: Store) { + constructor(private store: Store) { /** * Selectors can be applied with the `select` operator which passes the state * tree to the provided selector diff --git a/projects/example-app/src/app/core/reducers/layout.reducer.ts b/projects/example-app/src/app/core/reducers/layout.reducer.ts index 3ea44fd0dc..5278859bae 100644 --- a/projects/example-app/src/app/core/reducers/layout.reducer.ts +++ b/projects/example-app/src/app/core/reducers/layout.reducer.ts @@ -1,6 +1,5 @@ -import { - LayoutActions -} from '@example-app/core/actions'; +import { Action } from '@ngrx/store'; +import { LayoutActions } from '@example-app/core/actions'; export interface State { showSidenav: boolean; @@ -10,11 +9,10 @@ const initialState: State = { showSidenav: false, }; -export function reducer( - state: State = initialState, - action: LayoutActions.LayoutActionsUnion -): State { - switch (action.type) { +export function reducer(state: State = initialState, action: Action): State { + const specificAction = action as LayoutActions.LayoutActionsUnion; + + switch (specificAction.type) { case LayoutActions.LayoutActionTypes.CloseSidenav: return { showSidenav: false, diff --git a/projects/example-app/src/app/reducers/index.ts b/projects/example-app/src/app/reducers/index.ts index 3afb1a641a..6e67ef84aa 100644 --- a/projects/example-app/src/app/reducers/index.ts +++ b/projects/example-app/src/app/reducers/index.ts @@ -45,7 +45,7 @@ export const reducers: ActionReducerMap = { // console.log all actions export function logger(reducer: ActionReducer): ActionReducer { - return (state: State, action: any): any => { + return (state, action) => { const result = reducer(state, action); console.groupCollapsed(action.type); console.log('prev state', state); diff --git a/projects/example-app/tsconfig.app.json b/projects/example-app/tsconfig.app.json index af2f470570..eb33cfc924 100644 --- a/projects/example-app/tsconfig.app.json +++ b/projects/example-app/tsconfig.app.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "strict": true, + "strictPropertyInitialization": false, "sourceMap": true, "declaration": false, "moduleResolution": "node", diff --git a/projects/ngrx.io/content/guide/effects/testing.md b/projects/ngrx.io/content/guide/effects/testing.md index 85c4dcad33..20ed86d2fa 100644 --- a/projects/ngrx.io/content/guide/effects/testing.md +++ b/projects/ngrx.io/content/guide/effects/testing.md @@ -12,8 +12,7 @@ Usage: import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import { hot, cold } from 'jasmine-marbles'; +import { cold, hot } from 'jasmine-marbles'; import { Observable } from 'rxjs'; import { MyEffects } from './my-effects'; @@ -48,14 +47,44 @@ describe('My Effects', () => { expect(effects.someSource$).toBeObservable(expected); }); +}); + - it('should work also', () => { - actions = new ReplaySubject(1); +It is also possible to use `ReplaySubject` as an alternative for marble tests: + + +import { TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { ReplaySubject } from 'rxjs'; + +import { MyEffects } from './my-effects'; +import * as MyActions from '../actions/my-actions'; + +describe('My Effects', () => { + let effects: MyEffects; + let actions: ReplaySubject<any>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + // any modules needed + ], + providers: [ + MyEffects, + provideMockActions(() => actions), + // other providers + ], + }); - actions.next(SomeAction); + effects = TestBed.get(MyEffects); + }); + + it('should work', () => { + actions = new ReplaySubject(1); + actions.next(new MyActions.ExampleAction()); effects.someSource$.subscribe(result => { - expect(result).toEqual(AnotherAction); + expect(result).toEqual(new MyActions.ExampleActionSuccess()); }); }); }); diff --git a/projects/ngrx.io/content/marketing/resources.json b/projects/ngrx.io/content/marketing/resources.json index 6dbe1a23c7..f798182d62 100644 --- a/projects/ngrx.io/content/marketing/resources.json +++ b/projects/ngrx.io/content/marketing/resources.json @@ -69,6 +69,12 @@ "url": "https://github.com/avatsaev/angular-contacts-app-example", "rev": true }, + "angular-checklist": { + "title": "Angular Checklist", + "desc": "Curated list of common mistakes made when developing Angular applications", + "url": "https://angular-checklist.io", + "rev": true + }, "online-training": { "title": "Online Training website using ASP.Net Core 2.0 & Angular 4", diff --git a/projects/ngrx.io/src/404-body.html b/projects/ngrx.io/src/404-body.html index 3e6cf878fb..7794bc9c08 100644 --- a/projects/ngrx.io/src/404-body.html +++ b/projects/ngrx.io/src/404-body.html @@ -42,7 +42,7 @@

Resource Not Found