From d7fc5b56054c9a4c1fbb12845bfc0803f9a9ff86 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Fri, 17 Nov 2017 15:43:54 -0500 Subject: [PATCH] fix(schematics): --routing should add RouterTestingModule in app.component.spec.ts Closes #95 --- e2e/schematics/application.test.ts | 6 ++-- packages/schematics/src/app/app.spec.ts | 12 ++++++- packages/schematics/src/app/index.ts | 15 ++++++++- packages/schematics/src/lib/lib.spec.ts | 2 -- packages/schematics/src/utility/ast-utils.ts | 34 ++++++++++++++++---- 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/e2e/schematics/application.test.ts b/e2e/schematics/application.test.ts index 86ca80a3c1b40..0c281cfb3a93d 100644 --- a/e2e/schematics/application.test.ts +++ b/e2e/schematics/application.test.ts @@ -50,9 +50,10 @@ describe('Nrwl Workspace', () => { ngNew('--collection=@nrwl/schematics --npmScope=nrwl'); copyMissingPackages(); newApp('myapp --routing'); - newLib('mylib --ngmodule --routing --lazy --parentModule=apps/myapp/src/app/app.module.ts'); + newLib('mylib --routing --lazy --parentModule=apps/myapp/src/app/app.module.ts'); runCLI('build --aot'); + expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS'); }, 100000 ); @@ -63,9 +64,10 @@ describe('Nrwl Workspace', () => { ngNew('--collection=@nrwl/schematics --npmScope=nrwl'); copyMissingPackages(); newApp('myapp --routing'); - newLib('mylib --ngmodule --routing --parentModule=apps/myapp/src/app/app.module.ts'); + newLib('mylib --routing --parentModule=apps/myapp/src/app/app.module.ts'); runCLI('build --aot'); + expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS'); }, 100000 ); diff --git a/packages/schematics/src/app/app.spec.ts b/packages/schematics/src/app/app.spec.ts index 14bf4db6ccd66..da4ad57638f6e 100644 --- a/packages/schematics/src/app/app.spec.ts +++ b/packages/schematics/src/app/app.spec.ts @@ -39,7 +39,7 @@ describe('app', () => { }); it('should generate files', () => { - const tree = schematicRunner.runSchematic('app', { name: 'myAPp' }, appTree); + const tree = schematicRunner.runSchematic('app', { name: 'myApp' }, appTree); expect(tree.exists('apps/my-app/src/main.ts')).toBeTruthy(); expect(tree.exists('apps/my-app/src/app/app.module.ts')).toBeTruthy(); expect(tree.exists('apps/my-app/src/app/app.component.ts')).toBeTruthy(); @@ -51,4 +51,14 @@ describe('app', () => { const tree = schematicRunner.runSchematic('app', { name: 'myApp' }, appTree); expect(getFileContent(tree, 'apps/my-app/src/app/app.module.ts')).toContain('NxModule.forRoot()'); }); + + describe('routing', () => { + it('should include RouterTestingModule', () => { + const tree = schematicRunner.runSchematic('app', { name: 'myApp', routing: true }, appTree); + expect(getFileContent(tree, 'apps/my-app/src/app/app.module.ts')).toContain('RouterModule.forRoot'); + expect(getFileContent(tree, 'apps/my-app/src/app/app.component.spec.ts')).toContain( + 'imports: [RouterTestingModule]' + ); + }); + }); }); diff --git a/packages/schematics/src/app/index.ts b/packages/schematics/src/app/index.ts index 99c5701a3f12d..47267c3648bc5 100644 --- a/packages/schematics/src/app/index.ts +++ b/packages/schematics/src/app/index.ts @@ -21,6 +21,7 @@ import * as ts from 'typescript'; import { addBootstrapToModule } from '@schematics/angular/utility/ast-utils'; import { insertImport } from '@schematics/angular/utility/route-utils'; import { serializeJson, addApp } from '../utility/fileutils'; +import { addImportToTestBed } from '../utility/ast-utils'; function addBootstrap(path: string): Rule { return (host: Tree) => { @@ -91,8 +92,20 @@ function addRouterRootConfiguration(path: string): Rule { insertImport(sourceFile, modulePath, 'RouterModule', '@angular/router'), ...addImportToModule(sourceFile, modulePath, `RouterModule.forRoot([], {initialNavigation: 'enabled'})`) ]); + + const componentSpecPath = `${path}/app/app.component.spec.ts`; + const componentSpecSource = host.read(componentSpecPath)!.toString('utf-8'); + const componentSpecSourceFile = ts.createSourceFile( + componentSpecPath, + componentSpecSource, + ts.ScriptTarget.Latest, + true + ); + insert(host, componentSpecPath, [ + insertImport(componentSpecSourceFile, componentSpecPath, 'RouterTestingModule', '@angular/router/testing'), + ...addImportToTestBed(componentSpecSourceFile, componentSpecPath, `RouterTestingModule`) + ]); return host; - // add onSameUrlNavigation: 'reload' }; } diff --git a/packages/schematics/src/lib/lib.spec.ts b/packages/schematics/src/lib/lib.spec.ts index cbc68b7698c3a..a7a5d16ca790e 100644 --- a/packages/schematics/src/lib/lib.spec.ts +++ b/packages/schematics/src/lib/lib.spec.ts @@ -124,6 +124,4 @@ describe('lib', () => { }); }); }); - - // should throw when no --ngmodule }); diff --git a/packages/schematics/src/utility/ast-utils.ts b/packages/schematics/src/utility/ast-utils.ts index 93d78dd0533f3..32ef6d7088d25 100644 --- a/packages/schematics/src/utility/ast-utils.ts +++ b/packages/schematics/src/utility/ast-utils.ts @@ -234,6 +234,22 @@ export function addImportToModule(source: ts.SourceFile, modulePath: string, sym return _addSymbolToNgModuleMetadata(source, modulePath, 'imports', symbolName); } +export function addImportToTestBed(source: ts.SourceFile, specPath: string, symbolName: string): Change[] { + const allCalls: ts.CallExpression[] = findNodes(source, ts.SyntaxKind.CallExpression); + + const configureTestingModuleObjectLiterals = allCalls + .filter(c => c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) + .filter((c: any) => c.expression.name.getText(source) === 'configureTestingModule') + .map(c => (c.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression ? c.arguments[0] : null)); + + if (configureTestingModuleObjectLiterals.length > 0) { + const startPosition = configureTestingModuleObjectLiterals[0].getFirstToken(source).getEnd(); + return [new InsertChange(specPath, startPosition, `imports: [${symbolName}], `)]; + } else { + return []; + } +} + export function addReexport( source: ts.SourceFile, modulePath: string, @@ -269,13 +285,7 @@ export function getBootstrapComponent(source: ts.SourceFile, moduleClassName: st return bootstrapComponent.getText(); } -function getMatchingProperty(source: ts.SourceFile, property: string): ts.ObjectLiteralElement { - const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core'); - let node: any = nodes[0]; // tslint:disable-line:no-any - - if (!node) return null; - - // Get all the children property assignment of object literals. +function getMatchingObjectLiteralElement(node: any, source: ts.SourceFile, property: string) { return ( (node as ts.ObjectLiteralExpression).properties .filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment) @@ -294,6 +304,16 @@ function getMatchingProperty(source: ts.SourceFile, property: string): ts.Object ); } +function getMatchingProperty(source: ts.SourceFile, property: string): ts.ObjectLiteralElement { + const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core'); + let node: any = nodes[0]; // tslint:disable-line:no-any + + if (!node) return null; + + // Get all the children property assignment of object literals. + return getMatchingObjectLiteralElement(node, source, property); +} + export function addRoute(ngModulePath: string, source: ts.SourceFile, route: string): Change[] { const routes = getListOfRoutes(source); if (!routes) return [];