From 99bc13bf77941290f18b4957534d0c68c31401e3 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 14:03:35 -0500 Subject: [PATCH 1/9] feat: add success/failure effects/actions to ng generate feature --- .../__name@dasherize__.actions.ts | 16 +++++++++++-- .../__name@dasherize__.effects.ts | 23 +++++++++++++++++-- .../__name@dasherize__.reducer.ts | 16 ++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts index c633e3eb3a..5cc66eed55 100644 --- a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts +++ b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts @@ -1,11 +1,23 @@ import { Action } from '@ngrx/store'; export enum <%= classify(name) %>ActionTypes { - Load<%= classify(name) %>s = '[<%= classify(name) %>] Load <%= classify(name) %>s' + Load<%= classify(name) %>s = '[<%= classify(name) %>] Load <%= classify(name) %>s', + Load<%= classify(name) %>sSuccess = '[<%= classify(name) %>] Load <%= classify(name) %>s Success', + Load<%= classify(name) %>sFailure = '[<%= classify(name) %>] Load <%= classify(name) %>s Failure', } export class Load<%= classify(name) %>s implements Action { readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>s; } -export type <%= classify(name) %>Actions = Load<%= classify(name) %>s; +export class Load<%= classify(name) %>sSuccess implements Action { + readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess; + constructor(public payload: { data: any[] }) { } +} + +export class Load<%= classify(name) %>sFailure implements Action { + readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sFailure; + constructor(public payload: { error: any }) { } +} + +export type <%= classify(name) %>Actions = Load<%= classify(name) %>s | Load<%= classify(name) %>sSuccess | Load<%= classify(name) %>sFailure; diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts index e6f6ecdb98..7463ade948 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts @@ -1,12 +1,31 @@ import { Injectable } from '@angular/core'; import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects'; -<% if (feature) { %>import { <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> +<% if (feature) { %>import { catchError, map, switchMap } from 'rxjs/operators';<% } %> +<% if (feature) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> @Injectable() export class <%= classify(name) %>Effects { <% if (feature) { %> + + private _testObservable = of([ + { myDataProperty: 1000, myOtherDataProperty: 'some-text' }, + { myDataProperty: 1100, myOtherDataProperty: 'more-text' }] + ) + .pipe( + delay(1000), // simulate latency of 1 second + // (_ => { throw new Error('oops'); }) // uncomment to test error handling + ); + @Effect() - load<%= classify(name) %>s$ = this.actions$.pipe(ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s)); + load<%= classify(name) %>s$ = this.actions$.pipe( + ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>), + switchMap(() => + this._testObservable.pipe( + map(data => new Load<%= classify(name) %>sSuccess({ data })), + catchError(error => of(new Load<%= classify(name) %>sFailure({ error })))) + ) + ); <% } %> + constructor(private actions$: Actions) {} } diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts index d04b51cb80..1daa6b5099 100644 --- a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts +++ b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts @@ -2,18 +2,28 @@ import { Action } from '@ngrx/store'; <% if(feature) { %>import { <%= classify(name) %>Actions, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> export interface State { - + data: any[]; + loading: boolean; + error: any; } export const initialState: State = { - + data: null, + loading: false, + error: null }; export function reducer(state = initialState, action: <% if(feature) { %><%= classify(name) %>Actions<% } else { %>Action<% } %>): State { switch (action.type) { <% if(feature) { %> case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>s: - return state; + return { ...state, loading: true, error: null }; + + case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess: + return { ...state, data: action.payload.data, loading: false, error: null, }; + + case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sFailure: + return { ...state, loading: false, error: action.payload.error }; <% } %> default: From 674056f0b1ff89f9bc28d6e0f8e001d1d8ebaf31 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 15:25:18 -0500 Subject: [PATCH 2/9] feat: add/update unit tests for additional effects for success failure --- modules/schematics/src/action/index.spec.ts | 40 ++++++++++++++++++-- modules/schematics/src/effect/index.spec.ts | 19 ++++++---- modules/schematics/src/reducer/index.spec.ts | 22 +++++++++-- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/modules/schematics/src/action/index.spec.ts b/modules/schematics/src/action/index.spec.ts index f44c364741..2481bf3443 100644 --- a/modules/schematics/src/action/index.spec.ts +++ b/modules/schematics/src/action/index.spec.ts @@ -3,13 +3,13 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; -import { Schema as ActionOptions } from './schema'; import { - getTestProjectPath, createWorkspace, - defaultWorkspaceOptions, defaultAppOptions, + defaultWorkspaceOptions, + getTestProjectPath, } from '../../../schematics-core/testing'; +import { Schema as ActionOptions } from './schema'; describe('Action Schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -101,6 +101,36 @@ describe('Action Schematic', () => { expect(fileContent).toMatch(/export class LoadFoos implements Action/); }); + it('should create a class based on the provided name for success', () => { + const tree = schematicRunner.runSchematic( + 'action', + defaultOptions, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export class LoadFoosSuccess implements Action/ + ); + }); + + it('should create a class based on the provided name for failure', () => { + const tree = schematicRunner.runSchematic( + 'action', + defaultOptions, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export class LoadFoosFailure implements Action/ + ); + }); + it('should create the union type based on the provided name', () => { const tree = schematicRunner.runSchematic( 'action', @@ -111,7 +141,9 @@ describe('Action Schematic', () => { `${projectPath}/src/app/foo.actions.ts` ); - expect(fileContent).toMatch(/export type FooActions = LoadFoos/); + expect(fileContent).toMatch( + /export type FooActions = LoadFoos | LoadFoosSuccess | LoadFoosFailure;/ + ); }); it('should group within an "actions" folder if group is set', () => { diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index 16a2276c9f..1a793734fa 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -3,14 +3,14 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; -import { Schema as EffectOptions } from './schema'; import { - getTestProjectPath, - createWorkspace, createAppModuleWithEffects, - defaultWorkspaceOptions, + createWorkspace, defaultAppOptions, + defaultWorkspaceOptions, + getTestProjectPath, } from '../../../schematics-core/testing'; +import { Schema as EffectOptions } from './schema'; describe('Effect Schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -236,7 +236,7 @@ describe('Effect Schematic', () => { ); expect(content).toMatch( - /import \{ FooActionTypes } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ + /import \{ LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ ); }); @@ -251,11 +251,16 @@ describe('Effect Schematic', () => { /import { Actions, Effect, ofType } from '@ngrx\/effects';/ ); expect(content).toMatch( - /import { FooActionTypes } from '\.\/foo.actions';/ + /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ ); expect(content).toMatch(/export class FooEffects/); + expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); + expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); + expect(content).toMatch(/switchMap\(\(\) =>/); + expect(content).toMatch(/this\._testObservable\.pipe\(/); + expect(content).toMatch(/map\(data => new LoadFoosSuccess\({ data }\)\),/); expect(content).toMatch( - /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos\)\);/ + /catchError\(error => of\(new LoadFoosFailure\({ error }\)\)\)\)/ ); }); diff --git a/modules/schematics/src/reducer/index.spec.ts b/modules/schematics/src/reducer/index.spec.ts index f97c1aff88..5e61f1a404 100644 --- a/modules/schematics/src/reducer/index.spec.ts +++ b/modules/schematics/src/reducer/index.spec.ts @@ -3,14 +3,14 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; -import { Schema as ReducerOptions } from './schema'; import { - getTestProjectPath, createReducers, createWorkspace, - defaultWorkspaceOptions, defaultAppOptions, + defaultWorkspaceOptions, + getTestProjectPath, } from '../../../schematics-core/testing'; +import { Schema as ReducerOptions } from './schema'; describe('Reducer Schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -89,6 +89,22 @@ describe('Reducer Schematic', () => { expect(fileContent).toMatch(/export function reducer/); }); + it('should create a state with data, loading and error props', () => { + const tree = schematicRunner.runSchematic( + 'reducer', + defaultOptions, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.reducer.ts` + ); + + expect(fileContent).toMatch(/export interface State {/); + expect(fileContent).toMatch(/data: any\[\];/); + expect(fileContent).toMatch(/loading: boolean;/); + expect(fileContent).toMatch(/error: any;/); + }); + it('should import into a specified module', () => { const options = { ...defaultOptions, module: 'app.module.ts' }; From 4615abf189aaa73ba2b23fe51840834cca933343 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 16:11:02 -0500 Subject: [PATCH 3/9] feat: remove added state properties, revert some of the tests back to normal. wip --- modules/schematics/src/action/index.spec.ts | 10 ++++----- .../__name@dasherize__.reducer.ts | 14 +++++------- modules/schematics/src/reducer/index.spec.ts | 22 +++---------------- 3 files changed, 12 insertions(+), 34 deletions(-) diff --git a/modules/schematics/src/action/index.spec.ts b/modules/schematics/src/action/index.spec.ts index 2481bf3443..3caa8d274f 100644 --- a/modules/schematics/src/action/index.spec.ts +++ b/modules/schematics/src/action/index.spec.ts @@ -3,13 +3,13 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; +import { Schema as ActionOptions } from './schema'; import { + getTestProjectPath, createWorkspace, - defaultAppOptions, defaultWorkspaceOptions, - getTestProjectPath, + defaultAppOptions, } from '../../../schematics-core/testing'; -import { Schema as ActionOptions } from './schema'; describe('Action Schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -141,9 +141,7 @@ describe('Action Schematic', () => { `${projectPath}/src/app/foo.actions.ts` ); - expect(fileContent).toMatch( - /export type FooActions = LoadFoos | LoadFoosSuccess | LoadFoosFailure;/ - ); + expect(fileContent).toMatch(/export type FooActions = LoadFoos/); }); it('should group within an "actions" folder if group is set', () => { diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts index 1daa6b5099..6d698e0005 100644 --- a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts +++ b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts @@ -2,28 +2,24 @@ import { Action } from '@ngrx/store'; <% if(feature) { %>import { <%= classify(name) %>Actions, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> export interface State { - data: any[]; - loading: boolean; - error: any; + } export const initialState: State = { - data: null, - loading: false, - error: null + }; export function reducer(state = initialState, action: <% if(feature) { %><%= classify(name) %>Actions<% } else { %>Action<% } %>): State { switch (action.type) { <% if(feature) { %> case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>s: - return { ...state, loading: true, error: null }; + return state; case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess: - return { ...state, data: action.payload.data, loading: false, error: null, }; + return state; case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sFailure: - return { ...state, loading: false, error: action.payload.error }; + return state; <% } %> default: diff --git a/modules/schematics/src/reducer/index.spec.ts b/modules/schematics/src/reducer/index.spec.ts index 5e61f1a404..f97c1aff88 100644 --- a/modules/schematics/src/reducer/index.spec.ts +++ b/modules/schematics/src/reducer/index.spec.ts @@ -3,14 +3,14 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; +import { Schema as ReducerOptions } from './schema'; import { + getTestProjectPath, createReducers, createWorkspace, - defaultAppOptions, defaultWorkspaceOptions, - getTestProjectPath, + defaultAppOptions, } from '../../../schematics-core/testing'; -import { Schema as ReducerOptions } from './schema'; describe('Reducer Schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -89,22 +89,6 @@ describe('Reducer Schematic', () => { expect(fileContent).toMatch(/export function reducer/); }); - it('should create a state with data, loading and error props', () => { - const tree = schematicRunner.runSchematic( - 'reducer', - defaultOptions, - appTree - ); - const fileContent = tree.readContent( - `${projectPath}/src/app/foo.reducer.ts` - ); - - expect(fileContent).toMatch(/export interface State {/); - expect(fileContent).toMatch(/data: any\[\];/); - expect(fileContent).toMatch(/loading: boolean;/); - expect(fileContent).toMatch(/error: any;/); - }); - it('should import into a specified module', () => { const options = { ...defaultOptions, module: 'app.module.ts' }; From 7cb5bb2d0425756a9652cb3f9cdb2364c48a3363 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 16:13:06 -0500 Subject: [PATCH 4/9] feat: revert effect\index.spec.ts back to normal --- modules/schematics/src/effect/index.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index 1a793734fa..a183be66de 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -3,14 +3,14 @@ import { UnitTestTree, } from '@angular-devkit/schematics/testing'; import * as path from 'path'; +import { Schema as EffectOptions } from './schema'; import { - createAppModuleWithEffects, + getTestProjectPath, createWorkspace, - defaultAppOptions, + createAppModuleWithEffects, defaultWorkspaceOptions, - getTestProjectPath, + defaultAppOptions, } from '../../../schematics-core/testing'; -import { Schema as EffectOptions } from './schema'; describe('Effect Schematic', () => { const schematicRunner = new SchematicTestRunner( From 9012cc30feb635b6d843db9bc00e55bf830d5ac1 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 16:47:35 -0500 Subject: [PATCH 5/9] feat: adding api flag to schematics, cleaning up tests --- .../__name@dasherize__.actions.ts | 11 +++---- modules/schematics/src/action/index.spec.ts | 30 ------------------- modules/schematics/src/action/schema.json | 7 +++++ modules/schematics/src/action/schema.ts | 14 +++++++-- .../__name@dasherize__.effects.ts | 12 +++++--- modules/schematics/src/effect/index.spec.ts | 11 ++----- modules/schematics/src/effect/schema.json | 7 +++++ modules/schematics/src/effect/schema.ts | 16 ++++++++-- modules/schematics/src/feature/schema.json | 7 +++++ modules/schematics/src/feature/schema.ts | 15 +++++++--- modules/schematics/src/reducer/schema.json | 7 +++++ modules/schematics/src/reducer/schema.ts | 19 ++++++++---- 12 files changed, 94 insertions(+), 62 deletions(-) diff --git a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts index 5cc66eed55..4f4839cf88 100644 --- a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts +++ b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts @@ -2,14 +2,14 @@ import { Action } from '@ngrx/store'; export enum <%= classify(name) %>ActionTypes { Load<%= classify(name) %>s = '[<%= classify(name) %>] Load <%= classify(name) %>s', - Load<%= classify(name) %>sSuccess = '[<%= classify(name) %>] Load <%= classify(name) %>s Success', - Load<%= classify(name) %>sFailure = '[<%= classify(name) %>] Load <%= classify(name) %>s Failure', + <% if (api) { %>Load<%= classify(name) %>sSuccess = '[<%= classify(name) %>] Load <%= classify(name) %>s Success',<% } %> + <% if (api) { %>Load<%= classify(name) %>sFailure = '[<%= classify(name) %>] Load <%= classify(name) %>s Failure',<% } %> } export class Load<%= classify(name) %>s implements Action { readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>s; } - +<% if (api) { %> export class Load<%= classify(name) %>sSuccess implements Action { readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess; constructor(public payload: { data: any[] }) { } @@ -19,5 +19,6 @@ export class Load<%= classify(name) %>sFailure implements Action { readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sFailure; constructor(public payload: { error: any }) { } } - -export type <%= classify(name) %>Actions = Load<%= classify(name) %>s | Load<%= classify(name) %>sSuccess | Load<%= classify(name) %>sFailure; +<% } %> +<% if (api) { %>export type <%= classify(name) %>Actions = Load<%= classify(name) %>s | Load<%= classify(name) %>sSuccess | Load<%= classify(name) %>sFailure;<% } %> +<% if (!api) { %>export type <%= classify(name) %>Actions = Load<%= classify(name) %>s;<% } %> diff --git a/modules/schematics/src/action/index.spec.ts b/modules/schematics/src/action/index.spec.ts index 3caa8d274f..f44c364741 100644 --- a/modules/schematics/src/action/index.spec.ts +++ b/modules/schematics/src/action/index.spec.ts @@ -101,36 +101,6 @@ describe('Action Schematic', () => { expect(fileContent).toMatch(/export class LoadFoos implements Action/); }); - it('should create a class based on the provided name for success', () => { - const tree = schematicRunner.runSchematic( - 'action', - defaultOptions, - appTree - ); - const fileContent = tree.readContent( - `${projectPath}/src/app/foo.actions.ts` - ); - - expect(fileContent).toMatch( - /export class LoadFoosSuccess implements Action/ - ); - }); - - it('should create a class based on the provided name for failure', () => { - const tree = schematicRunner.runSchematic( - 'action', - defaultOptions, - appTree - ); - const fileContent = tree.readContent( - `${projectPath}/src/app/foo.actions.ts` - ); - - expect(fileContent).toMatch( - /export class LoadFoosFailure implements Action/ - ); - }); - it('should create the union type based on the provided name', () => { const tree = schematicRunner.runSchematic( 'action', diff --git a/modules/schematics/src/action/schema.json b/modules/schematics/src/action/schema.json index 1912889439..5ea9693891 100644 --- a/modules/schematics/src/action/schema.json +++ b/modules/schematics/src/action/schema.json @@ -38,6 +38,13 @@ "default": false, "description": "Group actions file within 'actions' folder", "aliases": ["g"] + }, + "api": { + "type": "boolean", + "default": false, + "description": + "Specifies if api success and failure actions should be generated.", + "aliases": ["a"] } }, "required": [] diff --git a/modules/schematics/src/action/schema.ts b/modules/schematics/src/action/schema.ts index fe74a3706b..735e90d43e 100644 --- a/modules/schematics/src/action/schema.ts +++ b/modules/schematics/src/action/schema.ts @@ -2,29 +2,37 @@ export interface Schema { /** * The name of the component. */ - name: string; + /** * The path to create the component. */ - path?: string; + /** * The name of the project. */ project?: string; + /** * Specifies if a spec file is generated. */ spec?: boolean; + /** * Flag to indicate if a dir is created. */ flat?: boolean; + /** * Group actions file within 'actions' folder */ - group?: boolean; + + /** + * Specifies if api success and failure actions + * should be generated. + */ + api?: boolean; } diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts index 7463ade948..cff3121895 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts @@ -1,11 +1,12 @@ import { Injectable } from '@angular/core'; import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects'; -<% if (feature) { %>import { catchError, map, switchMap } from 'rxjs/operators';<% } %> -<% if (feature) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> +<% if (feature && !api) { %>import { <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> +<% if (feature && api) { %>import { catchError, map, switchMap } from 'rxjs/operators';<% } %> +<% if (feature && api) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> @Injectable() export class <%= classify(name) %>Effects { -<% if (feature) { %> +<% if (feature && api) { %> private _testObservable = of([ { myDataProperty: 1000, myOtherDataProperty: 'some-text' }, @@ -26,6 +27,9 @@ export class <%= classify(name) %>Effects { ) ); <% } %> - +<% if (feature && !api) { %> + @Effect() + load<%= classify(name) %>s$ = this.actions$.pipe(ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s)); +<% } %> constructor(private actions$: Actions) {} } diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index a183be66de..16a2276c9f 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -236,7 +236,7 @@ describe('Effect Schematic', () => { ); expect(content).toMatch( - /import \{ LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ + /import \{ FooActionTypes } from \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ ); }); @@ -251,16 +251,11 @@ describe('Effect Schematic', () => { /import { Actions, Effect, ofType } from '@ngrx\/effects';/ ); expect(content).toMatch( - /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ + /import { FooActionTypes } from '\.\/foo.actions';/ ); expect(content).toMatch(/export class FooEffects/); - expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); - expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); - expect(content).toMatch(/switchMap\(\(\) =>/); - expect(content).toMatch(/this\._testObservable\.pipe\(/); - expect(content).toMatch(/map\(data => new LoadFoosSuccess\({ data }\)\),/); expect(content).toMatch( - /catchError\(error => of\(new LoadFoosFailure\({ error }\)\)\)\)/ + /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos\)\);/ ); }); diff --git a/modules/schematics/src/effect/schema.json b/modules/schematics/src/effect/schema.json index 217de2f781..7d29ab270d 100644 --- a/modules/schematics/src/effect/schema.json +++ b/modules/schematics/src/effect/schema.json @@ -56,6 +56,13 @@ "default": false, "description": "Group effects file within 'effects' folder", "aliases": ["g"] + }, + "api": { + "type": "boolean", + "default": false, + "description": + "Specifies if effect has api success and failure actions wired up", + "aliases": ["a"] } }, "required": [] diff --git a/modules/schematics/src/effect/schema.ts b/modules/schematics/src/effect/schema.ts index 611f357079..96b82a8e1b 100644 --- a/modules/schematics/src/effect/schema.ts +++ b/modules/schematics/src/effect/schema.ts @@ -2,40 +2,50 @@ export interface Schema { /** * The name of the component. */ - name: string; + /** * The path to create the effect. */ - path?: string; + /** * The name of the project. */ project?: string; + /** * Flag to indicate if a dir is created. */ flat?: boolean; + /** * Specifies if a spec file is generated. */ spec?: boolean; + /** * Allows specification of the declaring module. */ module?: string; + /** * Specifies if this is a root-level effect */ root?: boolean; + /** * Specifies if this is grouped within a feature */ feature?: boolean; + /** * Specifies if this is grouped within an 'effects' folder */ - group?: boolean; + + /** + * Specifies if effect has api success and failure actions wired up + */ + api?: boolean; } diff --git a/modules/schematics/src/feature/schema.json b/modules/schematics/src/feature/schema.json index 454398c537..f39099fbec 100644 --- a/modules/schematics/src/feature/schema.json +++ b/modules/schematics/src/feature/schema.json @@ -49,6 +49,13 @@ "description": "Group actions, reducers and effects within relative subfolders", "aliases": ["g"] + }, + "api": { + "type": "boolean", + "default": false, + "description": + "Specifies if api success and failure actions, reducer, and effects should be generated as part of this feature.", + "aliases": ["a"] } }, "required": [] diff --git a/modules/schematics/src/feature/schema.ts b/modules/schematics/src/feature/schema.ts index e88bc1adf9..08ac475cb2 100644 --- a/modules/schematics/src/feature/schema.ts +++ b/modules/schematics/src/feature/schema.ts @@ -3,38 +3,45 @@ export interface Schema { * The name of the feature. */ name: string; + /** * The path to create the feature. */ path?: string; + /** * The name of the project. */ project?: string; + /** * Flag to indicate if a dir is created. */ flat?: boolean; + /** * Specifies if a spec file is generated. */ spec?: boolean; + /** * Allows specification of the declaring module. */ - module?: string; + /** * Allows specification of the declaring reducers. */ - reducers?: string; + /** * Specifies if this is grouped within sub folders */ - group?: boolean; + /** - * Specifies if this is grouped within a feature + * Specifies if api success and failure actions, reducer, and effects + * should be generated as part of this feature. */ + api?: boolean; } diff --git a/modules/schematics/src/reducer/schema.json b/modules/schematics/src/reducer/schema.json index 78acb8bd0d..57a11e229e 100644 --- a/modules/schematics/src/reducer/schema.json +++ b/modules/schematics/src/reducer/schema.json @@ -53,6 +53,13 @@ "default": false, "description": "Group reducer file within 'reducers' folder", "aliases": ["g"] + }, + "api": { + "type": "boolean", + "default": false, + "description": + "Specifies if api success and failure actions should be added to the reducer", + "aliases": ["a"] } }, "required": [] diff --git a/modules/schematics/src/reducer/schema.ts b/modules/schematics/src/reducer/schema.ts index f3d3087f3e..32b1be51e7 100644 --- a/modules/schematics/src/reducer/schema.ts +++ b/modules/schematics/src/reducer/schema.ts @@ -3,41 +3,50 @@ export interface Schema { * The name of the component. */ name: string; + /** * The path to create the effect. */ - path?: string; + /** * The name of the project. */ project?: string; + /** * Flag to indicate if a dir is created. */ flat?: boolean; + /** * Specifies if a spec file is generated. */ spec?: boolean; + /** * Allows specification of the declaring module. */ - module?: string; + /** * Allows specification of the declaring reducers. */ - reducers?: string; + /** * Specifies if this is grouped within sub folders */ - group?: boolean; + /** * Specifies if this is grouped within a feature */ - feature?: boolean; + + /** + * Specifies if api success and failure actions + * should be added to the reducer. + */ + api?: boolean; } From 1a7bf879e29edaf8b5c8fd1bdaeb67c54329c716 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Fri, 25 Jan 2019 17:20:36 -0500 Subject: [PATCH 6/9] feat: implement api flag in templates, add new tests for schematics if api flag enabled --- modules/schematics/src/action/index.spec.ts | 54 +++++++++++++++ modules/schematics/src/effect/index.spec.ts | 28 ++++++++ modules/schematics/src/feature/index.spec.ts | 65 +++++++++++++++++++ modules/schematics/src/feature/index.ts | 3 + .../__name@dasherize__.reducer.ts | 5 +- modules/schematics/src/reducer/index.spec.ts | 18 +++++ 6 files changed, 170 insertions(+), 3 deletions(-) diff --git a/modules/schematics/src/action/index.spec.ts b/modules/schematics/src/action/index.spec.ts index f44c364741..9a780d257b 100644 --- a/modules/schematics/src/action/index.spec.ts +++ b/modules/schematics/src/action/index.spec.ts @@ -127,4 +127,58 @@ describe('Action Schematic', () => { tree.files.indexOf(`${projectPath}/src/app/actions/foo.actions.ts`) ).toBeGreaterThanOrEqual(0); }); + + it('should create a success class based on the provided name, given api', () => { + const tree = schematicRunner.runSchematic( + 'action', + { + ...defaultOptions, + api: true, + }, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export class LoadFoosSuccess implements Action/ + ); + }); + + it('should create a failure class based on the provided name, given api', () => { + const tree = schematicRunner.runSchematic( + 'action', + { + ...defaultOptions, + api: true, + }, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export class LoadFoosFailure implements Action/ + ); + }); + + it('should create the union type with success and failure based on the provided name, given api', () => { + const tree = schematicRunner.runSchematic( + 'action', + { + ...defaultOptions, + api: true, + }, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export type FooActions = LoadFoos \| LoadFoosSuccess \| LoadFoosFailure/ + ); + }); }); diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index 16a2276c9f..ac13558b14 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -277,4 +277,32 @@ describe('Effect Schematic', () => { /loadFoos\$ = this\.actions\$.pipe\(ofType\(FooActionTypes\.LoadFoos\)\);/ ); }); + + it('should create an api effect that describes a source of actions within a feature', () => { + const options = { ...defaultOptions, feature: true, api: true }; + + const tree = schematicRunner.runSchematic('effect', options, appTree); + const content = tree.readContent( + `${projectPath}/src/app/foo/foo.effects.ts` + ); + expect(content).toMatch( + /import { Actions, Effect, ofType } from '@ngrx\/effects';/ + ); + expect(content).toMatch( + /import { catchError, map, switchMap } from 'rxjs\/operators';/ + ); + expect(content).toMatch( + /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ + ); + + expect(content).toMatch(/export class FooEffects/); + expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); + expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); + expect(content).toMatch(/switchMap\(\(\) =>/); + expect(content).toMatch(/this\._testObservable\.pipe\(/); + expect(content).toMatch(/map\(data => new LoadFoosSuccess\({ data }\)\),/); + expect(content).toMatch( + /catchError\(error => of\(new LoadFoosFailure\({ error }\)\)\)\)/ + ); + }); }); diff --git a/modules/schematics/src/feature/index.spec.ts b/modules/schematics/src/feature/index.spec.ts index 24d0caf52d..e9850c98e4 100644 --- a/modules/schematics/src/feature/index.spec.ts +++ b/modules/schematics/src/feature/index.spec.ts @@ -126,4 +126,69 @@ describe('Feature Schematic', () => { /import \* as fromFoo from '\.\/foo\/reducers\/foo.reducer';/ ); }); + + it('should have all three api actions in actions type union if api flag enabled', () => { + const options = { + ...defaultOptions, + api: true, + }; + + const tree = schematicRunner.runSchematic('feature', options, appTree); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.actions.ts` + ); + + expect(fileContent).toMatch( + /export type FooActions = LoadFoos \| LoadFoosSuccess \| LoadFoosFailure/ + ); + }); + + it('should have all api effect if api flag enabled', () => { + const options = { + ...defaultOptions, + api: true, + }; + + const tree = schematicRunner.runSchematic('feature', options, appTree); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.effects.ts` + ); + + expect(fileContent).toMatch( + /import { Actions, Effect, ofType } from '@ngrx\/effects';/ + ); + expect(fileContent).toMatch( + /import { catchError, map, switchMap } from 'rxjs\/operators';/ + ); + expect(fileContent).toMatch( + /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ + ); + + expect(fileContent).toMatch(/export class FooEffects/); + expect(fileContent).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); + expect(fileContent).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); + expect(fileContent).toMatch(/switchMap\(\(\) =>/); + expect(fileContent).toMatch(/this\._testObservable\.pipe\(/); + expect(fileContent).toMatch( + /map\(data => new LoadFoosSuccess\({ data }\)\),/ + ); + expect(fileContent).toMatch( + /catchError\(error => of\(new LoadFoosFailure\({ error }\)\)\)\)/ + ); + }); + + it('should have all api actions in reducer if api flag enabled', () => { + const options = { + ...defaultOptions, + api: true, + }; + + const tree = schematicRunner.runSchematic('feature', options, appTree); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.reducer.ts` + ); + + expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosSuccess/); + expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosFailure/); + }); }); diff --git a/modules/schematics/src/feature/index.ts b/modules/schematics/src/feature/index.ts index a9b5abe1ac..cbde98c368 100644 --- a/modules/schematics/src/feature/index.ts +++ b/modules/schematics/src/feature/index.ts @@ -17,6 +17,7 @@ export default function(options: FeatureOptions): Rule { path: options.path, project: options.project, spec: false, + api: options.api, }), schematic('reducer', { flat: options.flat, @@ -28,6 +29,7 @@ export default function(options: FeatureOptions): Rule { spec: options.spec, reducers: options.reducers, feature: true, + api: options.api, }), schematic('effect', { flat: options.flat, @@ -38,6 +40,7 @@ export default function(options: FeatureOptions): Rule { project: options.project, spec: options.spec, feature: true, + api: options.api, }), ])(host, context); }; diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts index 6d698e0005..f7b48e35cd 100644 --- a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts +++ b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts @@ -14,14 +14,13 @@ export function reducer(state = initialState, action: <% if(feature) { %><%= cla <% if(feature) { %> case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>s: return state; - +<% if(api) { %> case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess: return state; case <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sFailure: return state; - -<% } %> +<% } %><% } %> default: return state; } diff --git a/modules/schematics/src/reducer/index.spec.ts b/modules/schematics/src/reducer/index.spec.ts index f97c1aff88..1d9256bed2 100644 --- a/modules/schematics/src/reducer/index.spec.ts +++ b/modules/schematics/src/reducer/index.spec.ts @@ -169,4 +169,22 @@ describe('Reducer Schematic', () => { /import\ \{\ FooActions,\ FooActionTypes\ }\ from\ \'\.\.\/\.\.\/actions\/foo\/foo\.actions';/ ); }); + + it('should create an reducer function with api success and failure, given feature and api', () => { + const tree = schematicRunner.runSchematic( + 'reducer', + { + ...defaultOptions, + feature: true, + api: true, + }, + appTree + ); + const fileContent = tree.readContent( + `${projectPath}/src/app/foo.reducer.ts` + ); + + expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosSuccess/); + expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosFailure/); + }); }); From 006a2bc92b2c8ea3799486d04e6989acc75d558f Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Mon, 28 Jan 2019 09:45:51 -0500 Subject: [PATCH 7/9] feat: schematics updates for api flag on features --- .../__name@dasherize__.actions.ts | 2 +- .../__name@dasherize__.effects.ts | 23 ++++++++----------- modules/schematics/src/effect/index.spec.ts | 13 +++++++---- modules/schematics/src/feature/index.spec.ts | 9 ++++---- .../__name@dasherize__.reducer.ts | 2 +- modules/schematics/src/reducer/index.spec.ts | 1 + 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts index 4f4839cf88..98cd8c8a93 100644 --- a/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts +++ b/modules/schematics/src/action/files/__name@dasherize@if-flat__/__name@dasherize__.actions.ts @@ -12,7 +12,7 @@ export class Load<%= classify(name) %>s implements Action { <% if (api) { %> export class Load<%= classify(name) %>sSuccess implements Action { readonly type = <%= classify(name) %>ActionTypes.Load<%= classify(name) %>sSuccess; - constructor(public payload: { data: any[] }) { } + constructor(public payload: { data: any }) { } } export class Load<%= classify(name) %>sFailure implements Action { diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts index cff3121895..cb34fa56ed 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts @@ -1,27 +1,18 @@ import { Injectable } from '@angular/core'; import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects'; +<% if (feature && api) { %>import { catchError, map, concatMap } from 'rxjs/operators';<% } %> +<% if (feature && api) { %>import { EMPTY, of } from 'rxjs';<% } %> +<% if (feature && api) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> <% if (feature && !api) { %>import { <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> -<% if (feature && api) { %>import { catchError, map, switchMap } from 'rxjs/operators';<% } %> -<% if (feature && api) { %>import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> @Injectable() export class <%= classify(name) %>Effects { <% if (feature && api) { %> - - private _testObservable = of([ - { myDataProperty: 1000, myOtherDataProperty: 'some-text' }, - { myDataProperty: 1100, myOtherDataProperty: 'more-text' }] - ) - .pipe( - delay(1000), // simulate latency of 1 second - // (_ => { throw new Error('oops'); }) // uncomment to test error handling - ); - @Effect() load<%= classify(name) %>s$ = this.actions$.pipe( ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>), - switchMap(() => - this._testObservable.pipe( + concatMap(() => + EMPTY.pipe( map(data => new Load<%= classify(name) %>sSuccess({ data })), catchError(error => of(new Load<%= classify(name) %>sFailure({ error })))) ) @@ -31,5 +22,9 @@ export class <%= classify(name) %>Effects { @Effect() load<%= classify(name) %>s$ = this.actions$.pipe(ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s)); <% } %> +<% if (feature && api) { %> + constructor(private actions$: Actions<<%= classify(name) %>Actions>) {} +<% } else { %> constructor(private actions$: Actions) {} +<% } %> } diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index ac13558b14..052724a1f5 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -289,20 +289,25 @@ describe('Effect Schematic', () => { /import { Actions, Effect, ofType } from '@ngrx\/effects';/ ); expect(content).toMatch( - /import { catchError, map, switchMap } from 'rxjs\/operators';/ + /import { catchError, map, concatMap } from 'rxjs\/operators';/ ); + expect(content).toMatch(/import { EMPTY, of } from 'rxjs';/); expect(content).toMatch( - /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ + /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes, FooActions } from '\.\/foo.actions';/ ); expect(content).toMatch(/export class FooEffects/); expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); - expect(content).toMatch(/switchMap\(\(\) =>/); - expect(content).toMatch(/this\._testObservable\.pipe\(/); + expect(content).toMatch(/concatMap\(\(\) =>/); + expect(content).toMatch(/EMPTY\.pipe\(/); expect(content).toMatch(/map\(data => new LoadFoosSuccess\({ data }\)\),/); expect(content).toMatch( /catchError\(error => of\(new LoadFoosFailure\({ error }\)\)\)\)/ ); + + expect(content).toMatch( + /constructor\(private actions\$: Actions\) {}/ + ); }); }); diff --git a/modules/schematics/src/feature/index.spec.ts b/modules/schematics/src/feature/index.spec.ts index e9850c98e4..06dc8445e3 100644 --- a/modules/schematics/src/feature/index.spec.ts +++ b/modules/schematics/src/feature/index.spec.ts @@ -158,17 +158,18 @@ describe('Feature Schematic', () => { /import { Actions, Effect, ofType } from '@ngrx\/effects';/ ); expect(fileContent).toMatch( - /import { catchError, map, switchMap } from 'rxjs\/operators';/ + /import { catchError, map, concatMap } from 'rxjs\/operators';/ ); + expect(fileContent).toMatch(/import { EMPTY, of } from 'rxjs';/); expect(fileContent).toMatch( - /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes } from '\.\/foo.actions';/ + /import { LoadFoosFailure, LoadFoosSuccess, FooActionTypes, FooActions } from '\.\/foo.actions';/ ); expect(fileContent).toMatch(/export class FooEffects/); expect(fileContent).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); expect(fileContent).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); - expect(fileContent).toMatch(/switchMap\(\(\) =>/); - expect(fileContent).toMatch(/this\._testObservable\.pipe\(/); + expect(fileContent).toMatch(/concatMap\(\(\) =>/); + expect(fileContent).toMatch(/EMPTY\.pipe\(/); expect(fileContent).toMatch( /map\(data => new LoadFoosSuccess\({ data }\)\),/ ); diff --git a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts index f7b48e35cd..7901446675 100644 --- a/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts +++ b/modules/schematics/src/reducer/files/__name@dasherize@if-flat__/__name@dasherize__.reducer.ts @@ -1,4 +1,4 @@ -import { Action } from '@ngrx/store'; +<% if(!feature) { %>import { Action } from '@ngrx/store';<% } %> <% if(feature) { %>import { <%= classify(name) %>Actions, <%= classify(name) %>ActionTypes } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %> export interface State { diff --git a/modules/schematics/src/reducer/index.spec.ts b/modules/schematics/src/reducer/index.spec.ts index 1d9256bed2..f060c579d3 100644 --- a/modules/schematics/src/reducer/index.spec.ts +++ b/modules/schematics/src/reducer/index.spec.ts @@ -186,5 +186,6 @@ describe('Reducer Schematic', () => { expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosSuccess/); expect(fileContent).toMatch(/case FooActionTypes\.LoadFoosFailure/); + expect(fileContent).not.toMatch(/import { Action } from '@ngrx\/store'/); }); }); From 8c059cbdd8d6a2f56d22ae6a1ebfc5ad29447a44 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Mon, 28 Jan 2019 11:04:48 -0500 Subject: [PATCH 8/9] feat: schematics add missing 's' to LoadFoos action type --- .../__name@dasherize@if-flat__/__name@dasherize__.effects.ts | 2 +- modules/schematics/src/effect/index.spec.ts | 2 +- modules/schematics/src/feature/index.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts index cb34fa56ed..c4f738a3e2 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts @@ -10,7 +10,7 @@ export class <%= classify(name) %>Effects { <% if (feature && api) { %> @Effect() load<%= classify(name) %>s$ = this.actions$.pipe( - ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>), + ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s), concatMap(() => EMPTY.pipe( map(data => new Load<%= classify(name) %>sSuccess({ data })), diff --git a/modules/schematics/src/effect/index.spec.ts b/modules/schematics/src/effect/index.spec.ts index 052724a1f5..76364a6fd2 100644 --- a/modules/schematics/src/effect/index.spec.ts +++ b/modules/schematics/src/effect/index.spec.ts @@ -298,7 +298,7 @@ describe('Effect Schematic', () => { expect(content).toMatch(/export class FooEffects/); expect(content).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); - expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); + expect(content).toMatch(/ofType\(FooActionTypes\.LoadFoos\),/); expect(content).toMatch(/concatMap\(\(\) =>/); expect(content).toMatch(/EMPTY\.pipe\(/); expect(content).toMatch(/map\(data => new LoadFoosSuccess\({ data }\)\),/); diff --git a/modules/schematics/src/feature/index.spec.ts b/modules/schematics/src/feature/index.spec.ts index 06dc8445e3..718db9e25a 100644 --- a/modules/schematics/src/feature/index.spec.ts +++ b/modules/schematics/src/feature/index.spec.ts @@ -167,7 +167,7 @@ describe('Feature Schematic', () => { expect(fileContent).toMatch(/export class FooEffects/); expect(fileContent).toMatch(/loadFoos\$ = this\.actions\$.pipe\(/); - expect(fileContent).toMatch(/ofType\(FooActionTypes\.LoadFoo\),/); + expect(fileContent).toMatch(/ofType\(FooActionTypes\.LoadFoos\),/); expect(fileContent).toMatch(/concatMap\(\(\) =>/); expect(fileContent).toMatch(/EMPTY\.pipe\(/); expect(fileContent).toMatch( From 809193812df440c4081cc6c3918c25500359d511 Mon Sep 17 00:00:00 2001 From: Wes Grimes Date: Mon, 28 Jan 2019 13:23:38 -0500 Subject: [PATCH 9/9] feat: schematics add comment explaining EMTPY observable --- .../__name@dasherize@if-flat__/__name@dasherize__.effects.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts index c4f738a3e2..5d9d9e84e2 100644 --- a/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts +++ b/modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts @@ -12,6 +12,7 @@ export class <%= classify(name) %>Effects { load<%= classify(name) %>s$ = this.actions$.pipe( ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s), concatMap(() => + /** An EMPTY observable only emits completion. Replace with your own observable API request */ EMPTY.pipe( map(data => new Load<%= classify(name) %>sSuccess({ data })), catchError(error => of(new Load<%= classify(name) %>sFailure({ error }))))