From 44e2dc39a440ef620c1f167e9f4e005ac7aec26c Mon Sep 17 00:00:00 2001 From: Stephen Cavaliere Date: Thu, 16 Mar 2017 21:29:46 -0400 Subject: [PATCH] refactor(@angular/cli): update generate command module file resolution closes #5461 --- .../cli/blueprints/component/index.ts | 21 ++- .../cli/blueprints/directive/index.ts | 40 +++--- .../@angular/cli/blueprints/guard/index.ts | 28 ++-- .../@angular/cli/blueprints/pipe/index.ts | 26 ++-- .../@angular/cli/blueprints/service/index.ts | 32 ++--- .../cli/utilities/resolve-module-file.ts | 46 ++++++ tests/acceptance/generate-component.spec.js | 93 +++++++++++++ tests/acceptance/generate-directive.spec.js | 94 ++++++++++++- tests/acceptance/generate-guard.spec.js | 131 ++++++++++++++---- tests/acceptance/generate-pipe.spec.js | 94 ++++++++++++- tests/acceptance/generate-service.spec.js | 93 +++++++++++++ 11 files changed, 580 insertions(+), 118 deletions(-) create mode 100644 packages/@angular/cli/utilities/resolve-module-file.ts diff --git a/packages/@angular/cli/blueprints/component/index.ts b/packages/@angular/cli/blueprints/component/index.ts index 38a0bd909059..258f9a70e49e 100644 --- a/packages/@angular/cli/blueprints/component/index.ts +++ b/packages/@angular/cli/blueprints/component/index.ts @@ -1,11 +1,12 @@ +import * as chalk from 'chalk'; +import * as fs from 'fs'; +import * as path from 'path'; import { NodeHost } from '../../lib/ast-tools'; import { CliConfig } from '../../models/config'; import { getAppFromConfig } from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as chalk from 'chalk'; const Blueprint = require('../../ember-cli/lib/models/blueprint'); const findParentModule = require('../../utilities/find-parent-module').default; const getFiles = Blueprint.prototype.files; @@ -107,14 +108,8 @@ export default Blueprint.extend({ beforeInstall: function (options: any) { const appConfig = getAppFromConfig(this.options.app); if (options.module) { - // Resolve path to module - const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`; - const parsedPath = dynamicPathParser(this.project, modulePath, appConfig); - this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base); - - if (!fs.existsSync(this.pathToModule)) { - throw 'Module specified does not exist'; - } + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); } else { try { this.pathToModule = findParentModule(this.project.root, appConfig.root, this.generatePath); @@ -135,7 +130,7 @@ export default Blueprint.extend({ const defaultPrefix = (appConfig && appConfig.prefix) || ''; let prefix = (this.options.prefix === 'false' || this.options.prefix === '') - ? '' : (this.options.prefix || defaultPrefix); + ? '' : (this.options.prefix || defaultPrefix); prefix = prefix && `${prefix}-`; this.selector = stringUtils.dasherize(prefix + parsedPath.name); diff --git a/packages/@angular/cli/blueprints/directive/index.ts b/packages/@angular/cli/blueprints/directive/index.ts index 6d7ce229af7f..0e17ee3d198b 100644 --- a/packages/@angular/cli/blueprints/directive/index.ts +++ b/packages/@angular/cli/blueprints/directive/index.ts @@ -1,11 +1,11 @@ -import {NodeHost} from '../../lib/ast-tools'; -import {CliConfig} from '../../models/config'; -import {getAppFromConfig} from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; - -const path = require('path'); -const fs = require('fs'); -const chalk = require('chalk'); +import * as chalk from 'chalk'; +import * as path from 'path'; +import { NodeHost } from '../../lib/ast-tools'; +import { CliConfig } from '../../models/config'; +import { getAppFromConfig } from '../../utilities/app-utils'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; + const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; @@ -58,17 +58,11 @@ export default Blueprint.extend({ } ], - beforeInstall: function(options: any) { + beforeInstall: function (options: any) { const appConfig = getAppFromConfig(this.options.app); if (options.module) { - // Resolve path to module - const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`; - const parsedPath = dynamicPathParser(this.project, modulePath, appConfig); - this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base); - - if (!fs.existsSync(this.pathToModule)) { - throw ' '; - } + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); } else { try { this.pathToModule = findParentModule(this.project.root, appConfig.root, this.generatePath); @@ -89,7 +83,7 @@ export default Blueprint.extend({ const defaultPrefix = (appConfig && appConfig.prefix) || ''; let prefix = (this.options.prefix === 'false' || this.options.prefix === '') - ? '' : (this.options.prefix || defaultPrefix); + ? '' : (this.options.prefix || defaultPrefix); prefix = prefix && `${prefix}-`; @@ -111,7 +105,7 @@ export default Blueprint.extend({ }; }, - files: function() { + files: function () { let fileList = getFiles.call(this) as Array; if (this.options && !this.options.spec) { @@ -135,7 +129,7 @@ export default Blueprint.extend({ }; }, - afterInstall: function(options: any) { + afterInstall: function (options: any) { const returns: Array = []; const className = stringUtils.classify(`${options.entity.name}Directive`); const fileName = stringUtils.dasherize(`${options.entity.name}.directive`); @@ -161,9 +155,9 @@ export default Blueprint.extend({ } return result; })); - this._writeStatusToUI(chalk.yellow, - 'update', - path.relative(this.project.root, this.pathToModule)); + this._writeStatusToUI(chalk.yellow, + 'update', + path.relative(this.project.root, this.pathToModule)); } return Promise.all(returns); diff --git a/packages/@angular/cli/blueprints/guard/index.ts b/packages/@angular/cli/blueprints/guard/index.ts index 6191292505da..5b3c8c233bcf 100644 --- a/packages/@angular/cli/blueprints/guard/index.ts +++ b/packages/@angular/cli/blueprints/guard/index.ts @@ -1,12 +1,12 @@ +import * as chalk from 'chalk'; +import * as path from 'path'; import { oneLine } from 'common-tags'; import { NodeHost } from '../../lib/ast-tools'; import { CliConfig } from '../../models/config'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; import { getAppFromConfig } from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; -const path = require('path'); -const fs = require('fs'); -const chalk = require('chalk'); const Blueprint = require('../../ember-cli/lib/models/blueprint'); const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); @@ -35,17 +35,11 @@ export default Blueprint.extend({ } ], - beforeInstall: function(options: any) { - const appConfig = getAppFromConfig(this.options.app); + beforeInstall: function (options: any) { if (options.module) { - // Resolve path to module - const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`; - const parsedPath = dynamicPathParser(this.project, modulePath, appConfig); - this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base); - - if (!fs.existsSync(this.pathToModule)) { - throw 'Module specified does not exist'; - } + const appConfig = getAppFromConfig(this.options.app); + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); } }, @@ -70,7 +64,7 @@ export default Blueprint.extend({ }; }, - files: function() { + files: function () { let fileList = getFiles.call(this) as Array; if (this.options && !this.options.spec) { @@ -114,8 +108,8 @@ export default Blueprint.extend({ astUtils.addProviderToModule(this.pathToModule, className, importPath) .then((change: any) => change.apply(NodeHost))); this._writeStatusToUI(chalk.yellow, - 'update', - path.relative(this.project.root, this.pathToModule)); + 'update', + path.relative(this.project.root, this.pathToModule)); } return Promise.all(returns); diff --git a/packages/@angular/cli/blueprints/pipe/index.ts b/packages/@angular/cli/blueprints/pipe/index.ts index 4ebc9fbb9012..9e440d4cc0a5 100644 --- a/packages/@angular/cli/blueprints/pipe/index.ts +++ b/packages/@angular/cli/blueprints/pipe/index.ts @@ -1,11 +1,11 @@ -import {NodeHost} from '../../lib/ast-tools'; -import {CliConfig} from '../../models/config'; -import {getAppFromConfig} from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; - -const path = require('path'); -const fs = require('fs'); -const chalk = require('chalk'); +import * as chalk from 'chalk'; +import * as path from 'path'; +import { NodeHost } from '../../lib/ast-tools'; +import { CliConfig } from '../../models/config'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; +import { getAppFromConfig } from '../../utilities/app-utils'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; + const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; @@ -56,14 +56,8 @@ export default Blueprint.extend({ beforeInstall: function(options: any) { const appConfig = getAppFromConfig(this.options.app); if (options.module) { - // Resolve path to module - const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`; - const parsedPath = dynamicPathParser(this.project, modulePath, appConfig); - this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base); - - if (!fs.existsSync(this.pathToModule)) { - throw 'Module specified does not exist'; - } + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); } else { try { this.pathToModule = findParentModule(this.project.root, appConfig.root, this.generatePath); diff --git a/packages/@angular/cli/blueprints/service/index.ts b/packages/@angular/cli/blueprints/service/index.ts index 4b4d7533f3be..e5254aa4f945 100644 --- a/packages/@angular/cli/blueprints/service/index.ts +++ b/packages/@angular/cli/blueprints/service/index.ts @@ -1,12 +1,12 @@ -import {NodeHost} from '../../lib/ast-tools'; -import {CliConfig} from '../../models/config'; -import {getAppFromConfig} from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; +import * as chalk from 'chalk'; +import * as path from 'path'; import { oneLine } from 'common-tags'; +import { NodeHost } from '../../lib/ast-tools'; +import { CliConfig } from '../../models/config'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; +import { getAppFromConfig } from '../../utilities/app-utils'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; -const path = require('path'); -const fs = require('fs'); -const chalk = require('chalk'); const Blueprint = require('../../ember-cli/lib/models/blueprint'); const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); @@ -40,17 +40,11 @@ export default Blueprint.extend({ } ], - beforeInstall: function(options: any) { + beforeInstall: function (options: any) { if (options.module) { - // Resolve path to module - const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`; const appConfig = getAppFromConfig(this.options.app); - const parsedPath = dynamicPathParser(this.project, modulePath, appConfig); - this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base); - - if (!fs.existsSync(this.pathToModule)) { - throw 'Module specified does not exist'; - } + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); } }, @@ -75,7 +69,7 @@ export default Blueprint.extend({ }; }, - files: function() { + files: function () { let fileList = getFiles.call(this) as Array; if (this.options && !this.options.spec) { @@ -119,8 +113,8 @@ export default Blueprint.extend({ astUtils.addProviderToModule(this.pathToModule, className, importPath) .then((change: any) => change.apply(NodeHost))); this._writeStatusToUI(chalk.yellow, - 'update', - path.relative(this.project.root, this.pathToModule)); + 'update', + path.relative(this.project.root, this.pathToModule)); } return Promise.all(returns); diff --git a/packages/@angular/cli/utilities/resolve-module-file.ts b/packages/@angular/cli/utilities/resolve-module-file.ts new file mode 100644 index 000000000000..9e8deb96576f --- /dev/null +++ b/packages/@angular/cli/utilities/resolve-module-file.ts @@ -0,0 +1,46 @@ +import * as path from 'path'; +import * as fs from 'fs'; +import { dynamicPathParser } from './dynamic-path-parser'; + +export function resolveModulePath( + moduleNameFromFlag: string, project: any, projectRoot: any, appConfig: any): string { + let baseModuleName = moduleNameFromFlag; + let parentFolders = ''; + + if (baseModuleName.includes(path.sep)) { + const splitPath = baseModuleName.split(path.sep); + baseModuleName = splitPath.pop(); + parentFolders = splitPath.join(path.sep); + } + + if (baseModuleName.includes('.')) { + baseModuleName = baseModuleName + .split('.') + .filter(part => part !== 'module' && part !== 'ts') + .join('.'); + } + + const baseModuleWithFileSuffix = `${baseModuleName}.module.ts`; + + const moduleRelativePath = path.join(parentFolders, baseModuleWithFileSuffix); + let fullModulePath = buildFullPath(project, moduleRelativePath, appConfig, projectRoot); + + if (!fs.existsSync(fullModulePath)) { + const moduleWithFolderPrefix = + path.join(parentFolders, baseModuleName, baseModuleWithFileSuffix); + fullModulePath = buildFullPath(project, moduleWithFolderPrefix, appConfig, projectRoot); + } + + if (!fs.existsSync(fullModulePath)) { + throw 'Specified module does not exist'; + } + + return fullModulePath; +} + +function buildFullPath(project: any, relativeModulePath: string, appConfig: any, projectRoot: any) { + const parsedPath = dynamicPathParser(project, relativeModulePath, appConfig); + const fullModulePath = path.join(projectRoot, parsedPath.dir, parsedPath.base); + + return fullModulePath; +} diff --git a/tests/acceptance/generate-component.spec.js b/tests/acceptance/generate-component.spec.js index 028308422506..d8be2a6cd0ee 100644 --- a/tests/acceptance/generate-component.spec.js +++ b/tests/acceptance/generate-component.spec.js @@ -222,4 +222,97 @@ describe('Acceptance: ng generate component', function () { expect(existsSync(testPath)).to.equal(false); }); }); + + it('should error out when given an incorrect module path', () => { + return Promise.resolve() + .then(() => ng(['generate', 'component', 'baz', '--module', 'foo'])) + .catch((error) => { + expect(error).to.equal('Specified module does not exist'); + }) + }); + + describe('should import and add to declaration list', () => { + it('when given a root level module with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'component', 'baz', '--module', 'app.module.ts'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazComponent\r?\n\s+\]/m); + }); + }); + + it('when given a root level module with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'component', 'baz', '--module', 'app'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazComponent\r?\n\s+\]/m); + }); + }); + + it('when given a submodule with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'component', 'baz', '--module', path.join('foo', 'foo.module.ts')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/..\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[BazComponent]/m); + }); + }); + + it('when given a submodule with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'component', 'baz', '--module', path.join('foo', 'foo')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/..\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[BazComponent]/m); + }); + }); + + it('when given a submodule folder', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'component', 'baz', '--module', 'foo'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/..\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[BazComponent]/m); + }); + }); + + it('when given deep submodule folder with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/bar/bar.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'module', path.join('foo', 'bar')])) + .then(() => ng(['generate', 'component', 'baz', '--module', path.join('foo', 'bar')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazComponent.*from '.\/..\/..\/baz\/baz.component';/); + expect(content).matches(/declarations:\s+\[BazComponent]/m); + }); + }); + }); }); diff --git a/tests/acceptance/generate-directive.spec.js b/tests/acceptance/generate-directive.spec.js index 0f4b214d0d71..66eae61abbda 100644 --- a/tests/acceptance/generate-directive.spec.js +++ b/tests/acceptance/generate-directive.spec.js @@ -13,7 +13,6 @@ const denodeify = require('denodeify'); const readFile = denodeify(fs.readFile); - describe('Acceptance: ng generate directive', function () { beforeEach(function () { return tmp.setup('./tmp').then(function () { @@ -178,4 +177,97 @@ describe('Acceptance: ng generate directive', function () { expect(content).matches(/selector: '\[appMyDir\]'/); }); }); + + it('should error out when given an incorrect module path', () => { + return Promise.resolve() + .then(() => ng(['generate', 'directive', 'baz', '--module', 'foo'])) + .catch((error) => { + expect(error).to.equal('Specified module does not exist'); + }) + }); + + describe('should import and add to declaration list', () => { + it('when given a root level module with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'directive', 'baz', '--module', 'app.module.ts'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/baz.directive';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazDirective\r?\n\s+\]/m); + }); + }); + + it('when given a root level module with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'directive', 'baz', '--module', 'app'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/baz.directive';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazDirective\r?\n\s+\]/m); + }); + }); + + it('when given a submodule with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'directive', 'baz', '--module', path.join('foo', 'foo.module.ts')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/..\/baz.directive';/); + expect(content).matches(/declarations:\s+\[BazDirective]/m); + }); + }); + + it('when given a submodule with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'directive', 'baz', '--module', path.join('foo', 'foo')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/..\/baz.directive';/); + expect(content).matches(/declarations:\s+\[BazDirective]/m); + }); + }); + + it('when given a submodule folder', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'directive', 'baz', '--module', 'foo'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/..\/baz.directive';/); + expect(content).matches(/declarations:\s+\[BazDirective]/m); + }); + }); + + it('when given deep submodule folder with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/bar/bar.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'module', path.join('foo', 'bar')])) + .then(() => ng(['generate', 'directive', 'baz', '--module', path.join('foo', 'bar')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazDirective.*from '.\/..\/..\/baz.directive';/); + expect(content).matches(/declarations:\s+\[BazDirective]/m); + }); + }); + }); }); diff --git a/tests/acceptance/generate-guard.spec.js b/tests/acceptance/generate-guard.spec.js index e6ed10fa4187..90a5be081563 100644 --- a/tests/acceptance/generate-guard.spec.js +++ b/tests/acceptance/generate-guard.spec.js @@ -14,21 +14,21 @@ const denodeify = require('denodeify'); const readFile = denodeify(fs.readFile); describe('Acceptance: ng generate guard', function () { - beforeEach(function () { - return tmp.setup('./tmp').then(function () { + beforeEach(() => { + return tmp.setup('./tmp').then(() => { process.chdir('./tmp'); - }).then(function () { + }).then(() => { return ng(['new', 'foo', '--skip-install']); }); }); - afterEach(function () { + afterEach(() => { this.timeout(10000); return tmp.teardown('./tmp'); }); - it('ng generate guard my-guard', function () { + it('ng generate guard my-guard', () => { const appRoot = path.join(root, 'tmp/foo'); const testPath = path.join(appRoot, 'src/app/my-guard.guard.ts'); const testSpecPath = path.join(appRoot, 'src/app/my-guard.guard.spec.ts'); @@ -41,12 +41,12 @@ describe('Acceptance: ng generate guard', function () { }) .then(() => readFile(appModulePath, 'utf-8')) .then(content => { - expect(content).not.to.matches(/import.*\MyGuardGuard\b.*from '.\/my-guard.guard';/); + expect(content).not.to.matches(/import.*MyGuardGuard.*from '.\/my-guard.guard';/); expect(content).not.to.matches(/providers:\s*\[MyGuardGuard\]/m); }); }); - it('ng generate guard my-guard --no-spec', function () { + it('ng generate guard my-guard --no-spec', () => { const appRoot = path.join(root, 'tmp/foo'); const testPath = path.join(appRoot, 'src/app/my-guard.guard.ts'); const testSpecPath = path.join(appRoot, 'src/app/my-guard.guard.spec.ts'); @@ -59,30 +59,12 @@ describe('Acceptance: ng generate guard', function () { }) .then(() => readFile(appModulePath, 'utf-8')) .then(content => { - expect(content).not.to.matches(/import.*\MyGuardGuard\b.*from '.\/my-guard.guard';/); + expect(content).not.to.matches(/import.*MyGuardGuard.*from '.\/my-guard.guard';/); expect(content).not.to.matches(/providers:\s*\[MyGuardGuard\]/m); }); }); - it('ng generate guard my-guard --module=app.module.ts', function () { - const appRoot = path.join(root, 'tmp/foo'); - const testPath = path.join(appRoot, 'src/app/my-guard.guard.ts'); - const testSpecPath = path.join(appRoot, 'src/app/my-guard.guard.spec.ts'); - const appModulePath = path.join(appRoot, 'src/app/app.module.ts'); - - return ng(['generate', 'guard', 'my-guard', '--module', 'app.module.ts']) - .then(() => { - expect(existsSync(testPath)).to.equal(true); - expect(existsSync(testSpecPath)).to.equal(true); - }) - .then(() => readFile(appModulePath, 'utf-8')) - .then(content => { - expect(content).to.matches(/import.*\MyGuardGuard\b.*from '.\/my-guard.guard';/); - expect(content).to.matches(/providers:\s*\[MyGuardGuard\]/m); - }); - }); - - it('ng generate guard test' + path.sep + 'my-guard', function () { + it('ng generate guard test' + path.sep + 'my-guard', () => { fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', 'test')); return ng(['generate', 'guard', 'test' + path.sep + 'my-guard']).then(() => { var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'test', 'my-guard.guard.ts'); @@ -90,7 +72,7 @@ describe('Acceptance: ng generate guard', function () { }); }); - it('ng generate guard test' + path.sep + '..' + path.sep + 'my-guard', function () { + it('ng generate guard test' + path.sep + '..' + path.sep + 'my-guard', () => { return ng(['generate', 'guard', 'test' + path.sep + '..' + path.sep + 'my-guard']).then(() => { var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-guard.guard.ts'); expect(existsSync(testPath)).to.equal(true); @@ -182,4 +164,97 @@ describe('Acceptance: ng generate guard', function () { expect(err).to.equal(`Invalid path: "..${path.sep}my-guard" cannot be above the "src${path.sep}app" directory`); }); }); + + it('should error out when given an incorrect module path', () => { + return Promise.resolve() + .then(() => ng(['generate', 'guard', 'baz', '--module', 'foo'])) + .catch((error) => { + expect(error).to.equal('Specified module does not exist'); + }) + }); + + describe('should import and add to provider list', () => { + it('when given a root level module with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'guard', 'baz', '--module', 'app.module.ts'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + + it('when given a root level module with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'guard', 'baz', '--module', 'app'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + + it('when given a submodule with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'guard', 'baz', '--module', path.join('foo', 'foo.module.ts')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/..\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + + it('when given a submodule with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'guard', 'baz', '--module', path.join('foo', 'foo')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/..\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + + it('when given a submodule folder', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'guard', 'baz', '--module', 'foo'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/..\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + + it('when given deep submodule folder with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/bar/bar.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'module', path.join('foo', 'bar')])) + .then(() => ng(['generate', 'guard', 'baz', '--module', path.join('foo', 'bar')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazGuard.*from '.\/..\/..\/baz.guard';/); + expect(content).to.matches(/providers:\s*\[BazGuard\]/m); + }); + }); + }); }); diff --git a/tests/acceptance/generate-pipe.spec.js b/tests/acceptance/generate-pipe.spec.js index 60e2e68ec388..96f113f35552 100644 --- a/tests/acceptance/generate-pipe.spec.js +++ b/tests/acceptance/generate-pipe.spec.js @@ -14,7 +14,6 @@ const denodeify = require('denodeify'); const readFile = denodeify(fs.readFile); - describe('Acceptance: ng generate pipe', function () { beforeEach(function () { return tmp.setup('./tmp').then(function () { @@ -156,4 +155,97 @@ describe('Acceptance: ng generate pipe', function () { expect(err).to.equal(`Invalid path: "..${path.sep}my-pipe" cannot be above the "src${path.sep}app" directory`); }); }); + + it('should error out when given an incorrect module path', () => { + return Promise.resolve() + .then(() => ng(['generate', 'pipe', 'baz', '--module', 'foo'])) + .catch((error) => { + expect(error).to.equal('Specified module does not exist'); + }) + }); + + describe('should import and add to declaration list', () => { + it('when given a root level module with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'pipe', 'baz', '--module', 'app.module.ts'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazPipe\r?\n\s+\]/m); + }); + }); + + it('when given a root level module with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'pipe', 'baz', '--module', 'app'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[\r?\n\s+AppComponent,\r?\n\s+BazPipe\r?\n\s+\]/m); + }); + }); + + it('when given a submodule with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'pipe', 'baz', '--module', path.join('foo', 'foo.module.ts')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/..\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[BazPipe]/m); + }); + }); + + it('when given a submodule with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'pipe', 'baz', '--module', path.join('foo', 'foo')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/..\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[BazPipe]/m); + }); + }); + + it('when given a submodule folder', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'pipe', 'baz', '--module', 'foo'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/..\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[BazPipe]/m); + }); + }); + + it('when given deep submodule folder with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/bar/bar.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'module', path.join('foo', 'bar')])) + .then(() => ng(['generate', 'pipe', 'baz', '--module', path.join('foo', 'bar')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).matches(/import.*BazPipe.*from '.\/..\/..\/baz.pipe';/); + expect(content).matches(/declarations:\s+\[BazPipe]/m); + }); + }); + }); }); diff --git a/tests/acceptance/generate-service.spec.js b/tests/acceptance/generate-service.spec.js index 7a34924ab882..69895443301d 100644 --- a/tests/acceptance/generate-service.spec.js +++ b/tests/acceptance/generate-service.spec.js @@ -165,4 +165,97 @@ describe('Acceptance: ng generate service', function () { expect(err).to.equal(`Invalid path: "..${path.sep}my-svc" cannot be above the "src${path.sep}app" directory`); }); }); + + it('should error out when given an incorrect module path', () => { + return Promise.resolve() + .then(() => ng(['generate', 'service', 'baz', '--module', 'foo'])) + .catch((error) => { + expect(error).to.equal('Specified module does not exist'); + }) + }); + + describe('should import and add to provider list', () => { + it('when given a root level module with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'service', 'baz', '--module', 'app.module.ts'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + + it('when given a root level module with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/app.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'service', 'baz', '--module', 'app'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + + it('when given a submodule with module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'service', 'baz', '--module', path.join('foo', 'foo.module.ts')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/..\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + + it('when given a submodule with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'service', 'baz', '--module', path.join('foo', 'foo')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/..\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + + it('when given a submodule folder', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/foo.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'service', 'baz', '--module', 'foo'])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/..\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + + it('when given deep submodule folder with missing module.ts suffix', () => { + const appRoot = path.join(root, 'tmp/foo'); + const modulePath = path.join(appRoot, 'src/app/foo/bar/bar.module.ts'); + + return Promise.resolve() + .then(() => ng(['generate', 'module', 'foo'])) + .then(() => ng(['generate', 'module', path.join('foo', 'bar')])) + .then(() => ng(['generate', 'service', 'baz', '--module', path.join('foo', 'bar')])) + .then(() => readFile(modulePath, 'utf-8')) + .then(content => { + expect(content).to.matches(/import.*BazService.*from '.\/..\/..\/baz.service';/); + expect(content).to.matches(/providers:\s*\[BazService\]/m); + }); + }); + }); });