From 77568829c25538dab6ca6102bc7d5c83014eacae Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 9 Aug 2018 16:45:45 +0200 Subject: [PATCH] refactor(schematics): run tests for template files (#12562) --- src/lib/schematics/BUILD.bazel | 30 +++---------- src/lib/schematics/address-form/schema.json | 12 +++++- src/lib/schematics/collection.json | 8 +++- src/lib/schematics/dashboard/index.spec.ts | 7 +-- src/lib/schematics/dashboard/schema.json | 6 ++- src/lib/schematics/install/index.spec.ts | 2 +- src/lib/schematics/nav/index.spec.ts | 7 +-- src/lib/schematics/nav/schema.json | 6 ++- src/lib/schematics/table/index.spec.ts | 7 +-- src/lib/schematics/table/schema.json | 6 ++- .../schematics/test-setup/bazel-test-init.ts | 43 +++++++++++++++++++ .../post-scheduled-tasks.ts} | 29 +------------ src/lib/schematics/test-setup/test-app.ts | 36 ++++++++++++++++ src/lib/schematics/tree/schema.json | 12 +++++- src/lib/schematics/tsconfig.json | 2 + .../update/test-cases/index.spec.ts | 3 +- src/lib/schematics/update/update.spec.ts | 12 +----- src/lib/schematics/utils/get-project.ts | 2 +- tslint.json | 5 +-- 19 files changed, 143 insertions(+), 92 deletions(-) create mode 100644 src/lib/schematics/test-setup/bazel-test-init.ts rename src/lib/schematics/{utils/testing.ts => test-setup/post-scheduled-tasks.ts} (62%) create mode 100644 src/lib/schematics/test-setup/test-app.ts diff --git a/src/lib/schematics/BUILD.bazel b/src/lib/schematics/BUILD.bazel index 76c5a52a6ee..8d0372fb35a 100644 --- a/src/lib/schematics/BUILD.bazel +++ b/src/lib/schematics/BUILD.bazel @@ -12,7 +12,12 @@ filegroup( ts_library( name = "schematics", module_name = "@angular/material/schematics", - srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts", "update/test-cases/**/*.ts", "**/files/**/*"]), + srcs = glob(["**/*.ts"], exclude=[ + "**/*.spec.ts", + "**/files/**/*", + "test-setup/**/*", + "update/test-cases/**/*", + ]), tsconfig = ":tsconfig.json", ) @@ -30,12 +35,11 @@ jasmine_node_test( name = "unit_tests", srcs = [":schematics_test_sources"], data = [":schematics_assets", ":schematics_test_cases"], - deps = [":copy-collection-file", ":copy-migration-file"], ) ts_library( name = "schematics_test_sources", - srcs = glob(["**/*.spec.ts"], exclude=["**/files/**/*"]), + srcs = glob(["**/*.spec.ts", "test-setup/**/*.ts"], exclude=["**/files/**/*"]), deps = [":schematics"], tsconfig = ":tsconfig.json", testonly = True, @@ -46,23 +50,3 @@ filegroup( srcs = glob(["update/test-cases/**/*_input.ts", "update/test-cases/**/*_expected_output.ts"]), testonly = True, ) - -# Workaround for https://github.com/bazelbuild/rules_typescript/issues/154 -genrule( - name = "copy-collection-file", - srcs = ["collection.json"], - outs = ["test-collection.json"], - cmd = "cp $< $@", - output_to_bindir = True, - testonly = True, -) - -# Workaround for https://github.com/bazelbuild/rules_typescript/issues/154 -genrule( - name = "copy-migration-file", - srcs = ["migration.json"], - outs = ["test-migration.json"], - cmd = "cp $< $@", - output_to_bindir = True, - testonly = True, -) diff --git a/src/lib/schematics/address-form/schema.json b/src/lib/schematics/address-form/schema.json index 7e209d744a4..a1cc0c4629b 100644 --- a/src/lib/schematics/address-form/schema.json +++ b/src/lib/schematics/address-form/schema.json @@ -13,7 +13,9 @@ "project": { "type": "string", "description": "The name of the project.", - "visible": false + "$default": { + "$source": "projectName" + } }, "name": { "type": "string", @@ -88,6 +90,12 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } - } + }, + "required": [] } diff --git a/src/lib/schematics/collection.json b/src/lib/schematics/collection.json index e796c78f088..f0c18f03027 100644 --- a/src/lib/schematics/collection.json +++ b/src/lib/schematics/collection.json @@ -6,24 +6,28 @@ "ng-add": { "description": "Adds Angular Material to the application without affecting any templates", "factory": "./install", + "schema": "./install/schema.json", "aliases": ["material-shell"] }, // Create a dashboard component "dashboard": { "description": "Create a card-based dashboard component", "factory": "./dashboard/index", + "schema": "./dashboard/schema.json", "aliases": ["material-dashboard"] }, // Creates a table component "table": { "description": "Create a component that displays data with a data-table", "factory": "./table/index", + "schema": "./table/schema.json", "aliases": ["material-table"] }, // Creates toolbar and navigation components "nav": { "description": "Create a component with a responsive sidenav for navigation", "factory": "./nav/index", + "schema": "./nav/schema.json", // TODO(devversion): re-add `materialNav` alias if we have the latest schematics version // that includes https://github.com/angular/angular-cli/pull/11390 "aliases": [ "material-nav"] @@ -31,12 +35,14 @@ // Create a file tree component "tree": { "description": "Create a file tree component.", - "factory": "./tree/index" + "factory": "./tree/index", + "schema": "./tree/schema.json" }, // Creates a address form component "addressForm": { "description": "Create a component with a address form", "factory": "./address-form/index", + "schema": "./address-form/schema.json", "aliases": ["address-form"] } } diff --git a/src/lib/schematics/dashboard/index.spec.ts b/src/lib/schematics/dashboard/index.spec.ts index fe3b45a592c..75bd231dd27 100644 --- a/src/lib/schematics/dashboard/index.spec.ts +++ b/src/lib/schematics/dashboard/index.spec.ts @@ -1,5 +1,5 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {createTestApp, collectionPath} from '../utils/testing'; +import {collectionPath, createTestApp} from '../test-setup/test-app'; import {getFileContent} from '@schematics/angular/utility/test'; import {Schema} from './schema'; @@ -18,10 +18,7 @@ describe('material-dashboard-schematic', () => { runner = new SchematicTestRunner('schematics', collectionPath); }); - // TODO(devversion): Temporarily disabled because @angular-devkit/schematics is not able to - // find the template files for the schematic. As soon as we find a way to properly reference - // those files, we can re-enable this test. - xit('should create dashboard files and add them to module', () => { + it('should create dashboard files and add them to module', () => { const tree = runner.runSchematic('dashboard', { ...options }, createTestApp()); const files = tree.files; diff --git a/src/lib/schematics/dashboard/schema.json b/src/lib/schematics/dashboard/schema.json index babda250d91..0d5075b9958 100644 --- a/src/lib/schematics/dashboard/schema.json +++ b/src/lib/schematics/dashboard/schema.json @@ -13,7 +13,6 @@ "project": { "type": "string", "description": "The name of the project.", - "visible": false, "$default": { "$source": "projectName" } @@ -91,6 +90,11 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } }, "required": [] diff --git a/src/lib/schematics/install/index.spec.ts b/src/lib/schematics/install/index.spec.ts index 1149cbd6632..c2a4ed3bc45 100644 --- a/src/lib/schematics/install/index.spec.ts +++ b/src/lib/schematics/install/index.spec.ts @@ -2,7 +2,7 @@ import {Tree} from '@angular-devkit/schematics'; import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {getProjectFromWorkspace} from '../utils/get-project'; import {getFileContent} from '@schematics/angular/utility/test'; -import {collectionPath, createTestApp} from '../utils/testing'; +import {collectionPath, createTestApp} from '../test-setup/test-app'; import {getWorkspace} from '@schematics/angular/utility/config'; import {getIndexHtmlPath} from '../utils/ast'; import {normalize} from '@angular-devkit/core'; diff --git a/src/lib/schematics/nav/index.spec.ts b/src/lib/schematics/nav/index.spec.ts index 85575075021..37af2ca83cf 100644 --- a/src/lib/schematics/nav/index.spec.ts +++ b/src/lib/schematics/nav/index.spec.ts @@ -1,7 +1,7 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {Schema} from './schema'; import {getFileContent} from '@schematics/angular/utility/test'; -import {collectionPath, createTestApp} from '../utils/testing'; +import {collectionPath, createTestApp} from '../test-setup/test-app'; describe('material-nav-schematic', () => { let runner: SchematicTestRunner; @@ -19,10 +19,7 @@ describe('material-nav-schematic', () => { runner = new SchematicTestRunner('schematics', collectionPath); }); - // TODO(devversion): Temporarily disabled because @angular-devkit/schematics is not able to - // find the template files for the schematic. As soon as we find a way to properly reference - // those files, we can re-enable this test. - xit('should create nav files and add them to module', () => { + it('should create nav files and add them to module', () => { const tree = runner.runSchematic('nav', { ...options }, createTestApp()); const files = tree.files; diff --git a/src/lib/schematics/nav/schema.json b/src/lib/schematics/nav/schema.json index 1c728872fd4..ab0ab41202a 100644 --- a/src/lib/schematics/nav/schema.json +++ b/src/lib/schematics/nav/schema.json @@ -13,7 +13,6 @@ "project": { "type": "string", "description": "The name of the project.", - "visible": false, "$default": { "$source": "projectName" } @@ -91,6 +90,11 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } }, "required": [] diff --git a/src/lib/schematics/table/index.spec.ts b/src/lib/schematics/table/index.spec.ts index 3098a25e4b8..5b32f7fea18 100644 --- a/src/lib/schematics/table/index.spec.ts +++ b/src/lib/schematics/table/index.spec.ts @@ -1,7 +1,7 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {Schema} from './schema'; import {getFileContent} from '@schematics/angular/utility/test'; -import {collectionPath, createTestApp} from '../utils/testing'; +import {collectionPath, createTestApp} from '../test-setup/test-app'; describe('material-table-schematic', () => { let runner: SchematicTestRunner; @@ -19,10 +19,7 @@ describe('material-table-schematic', () => { runner = new SchematicTestRunner('schematics', collectionPath); }); - // TODO(devversion): Temporarily disabled because @angular-devkit/schematics is not able to - // find the template files for the schematic. As soon as we find a way to properly reference - // those files, we can re-enable this test. - xit('should create table files and add them to module', () => { + it('should create table files and add them to module', () => { const tree = runner.runSchematic('table', { ...options }, createTestApp()); const files = tree.files; diff --git a/src/lib/schematics/table/schema.json b/src/lib/schematics/table/schema.json index af8921b296b..89a07cd18a1 100644 --- a/src/lib/schematics/table/schema.json +++ b/src/lib/schematics/table/schema.json @@ -13,7 +13,6 @@ "project": { "type": "string", "description": "The name of the project.", - "visible": false, "$default": { "$source": "projectName" } @@ -91,6 +90,11 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } }, "required": [] diff --git a/src/lib/schematics/test-setup/bazel-test-init.ts b/src/lib/schematics/test-setup/bazel-test-init.ts new file mode 100644 index 00000000000..e0de57c8ec6 --- /dev/null +++ b/src/lib/schematics/test-setup/bazel-test-init.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/* + * NOTE: This file will run before the actual tests start inside of Bazel. + * + * It automatically runs before all spec files because the spec files are blocked + * until Jasmine runs the `describe` blocks. + * + * We copy all needed files into the proper Bazel bin output in order to be able to test + * the schematics. Workaround for: https://github.com/bazelbuild/rules_typescript/issues/154 + */ + +import {sync as globSync} from 'glob'; +import {dirname, join} from 'path'; +import {copySync} from 'fs-extra'; + +// Adding the test case files to the data of the `jasmine_node_test` Bazel rule does not mean +// that the files are being copied over to the Bazel bin output. Bazel just patches the NodeJS +// resolve function and maps the module paths to the original file location. Since we want to copy +// the files to the bazel test directory because TSLint and the schematic test runner expect a real +// file system, we need to resolve the original file path through a Bazel mapped file. +const sourceDirectory = dirname( + require.resolve('angular_material/src/lib/schematics/collection.json')); + +const bazelBinDir = join(__dirname, '../'); + +// Copy all schema files to the bazel bin directory. +globSync('**/schema.json', {cwd: sourceDirectory}) + .forEach(file => copySync(join(sourceDirectory, file), join(bazelBinDir, file))); + +// Copy all template files to the bazel bin directory. +globSync('**/files/**/*', {cwd: sourceDirectory}) + .forEach(file => copySync(join(sourceDirectory, file), join(bazelBinDir, file))); + +// Copy the collection.json and migration.json file to the bazel bin directory. +globSync('+(collection|migration).json', {cwd: sourceDirectory}) + .forEach(file => copySync(join(sourceDirectory, file), join(bazelBinDir, file))); diff --git a/src/lib/schematics/utils/testing.ts b/src/lib/schematics/test-setup/post-scheduled-tasks.ts similarity index 62% rename from src/lib/schematics/utils/testing.ts rename to src/lib/schematics/test-setup/post-scheduled-tasks.ts index 7e5ef605713..994dca55954 100644 --- a/src/lib/schematics/utils/testing.ts +++ b/src/lib/schematics/test-setup/post-scheduled-tasks.ts @@ -7,37 +7,10 @@ */ import {EngineHost, TaskScheduler} from '@angular-devkit/schematics'; -import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; -import {join} from 'path'; +import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {from as observableFrom, Observable} from 'rxjs'; import {concatMap, filter, last} from 'rxjs/operators'; -/** Path to the test collection file for the Material schematics */ -export const collectionPath = join(__dirname, '..', 'test-collection.json'); - -/** Path to the test migration file for the Material update schematics */ -export const migrationCollection = join(__dirname, '..', 'test-migration.json'); - -/** Create a base app used for testing. */ -export function createTestApp(): UnitTestTree { - const baseRunner = new SchematicTestRunner('material-schematics', collectionPath); - - const workspaceTree = baseRunner.runExternalSchematic('@schematics/angular', 'workspace', { - name: 'workspace', - version: '6.0.0', - newProjectRoot: 'projects', - }); - - return baseRunner.runExternalSchematic('@schematics/angular', 'application', { - name: 'material', - inlineStyle: false, - inlineTemplate: false, - routing: false, - style: 'scss', - skipTests: false, - }, workspaceTree); -} - /** * Due to the fact that the Angular devkit does not support running scheduled tasks from a * schematic that has been launched through the TestRunner, we need to manually find the task diff --git a/src/lib/schematics/test-setup/test-app.ts b/src/lib/schematics/test-setup/test-app.ts new file mode 100644 index 00000000000..65ce9587074 --- /dev/null +++ b/src/lib/schematics/test-setup/test-app.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; +import {join} from 'path'; + +/** Path to the collection file for the Material schematics */ +export const collectionPath = join(__dirname, '..', 'collection.json'); + +/** Path to the migration file for the Material update schematics */ +export const migrationCollection = join(__dirname, '..', 'migration.json'); + +/** Create a base app used for testing. */ +export function createTestApp(): UnitTestTree { + const baseRunner = new SchematicTestRunner('material-schematics', collectionPath); + + const workspaceTree = baseRunner.runExternalSchematic('@schematics/angular', 'workspace', { + name: 'workspace', + version: '6.0.0', + newProjectRoot: 'projects', + }); + + return baseRunner.runExternalSchematic('@schematics/angular', 'application', { + name: 'material', + inlineStyle: false, + inlineTemplate: false, + routing: false, + style: 'scss', + skipTests: false, + }, workspaceTree); +} diff --git a/src/lib/schematics/tree/schema.json b/src/lib/schematics/tree/schema.json index 5245bbb4d34..d76921c4a0a 100644 --- a/src/lib/schematics/tree/schema.json +++ b/src/lib/schematics/tree/schema.json @@ -13,7 +13,9 @@ "project": { "type": "string", "description": "The name of the project.", - "visible": false + "$default": { + "$source": "projectName" + } }, "name": { "type": "string", @@ -88,6 +90,12 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } - } + }, + "required": [] } diff --git a/src/lib/schematics/tsconfig.json b/src/lib/schematics/tsconfig.json index 088bd456d5e..9c1cb6bd49f 100644 --- a/src/lib/schematics/tsconfig.json +++ b/src/lib/schematics/tsconfig.json @@ -16,6 +16,8 @@ }, "exclude": [ "**/*.spec.ts", + // Exclude the test-setup utility files. Those should not be part of the output. + "test-setup/**/*", // Exclude template files that will be copied by the schematics. Those are not valid TS. "*/files/**/*", // Exclude all test-case files because those should not be included in the schematics output. diff --git a/src/lib/schematics/update/test-cases/index.spec.ts b/src/lib/schematics/update/test-cases/index.spec.ts index 5b0e5560586..72161a4120f 100644 --- a/src/lib/schematics/update/test-cases/index.spec.ts +++ b/src/lib/schematics/update/test-cases/index.spec.ts @@ -2,7 +2,8 @@ import {getSystemPath, normalize, virtualFs} from '@angular-devkit/core'; import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing'; import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {readFileSync} from 'fs'; -import {createTestApp, migrationCollection, runPostScheduledTasks} from '../../utils/testing'; +import {runPostScheduledTasks} from '../../test-setup/post-scheduled-tasks'; +import {createTestApp, migrationCollection} from '../../test-setup/test-app'; describe('test cases', () => { diff --git a/src/lib/schematics/update/update.spec.ts b/src/lib/schematics/update/update.spec.ts index f70a5114072..b2ac0897721 100644 --- a/src/lib/schematics/update/update.spec.ts +++ b/src/lib/schematics/update/update.spec.ts @@ -1,11 +1 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {migrationCollection} from '../utils/testing'; - -describe('material-nav-schematic', () => { - let runner: SchematicTestRunner; - - beforeEach(() => { - runner = new SchematicTestRunner('schematics', migrationCollection); - }); - -}); +describe('material-nav-schematic', () => {}); diff --git a/src/lib/schematics/utils/get-project.ts b/src/lib/schematics/utils/get-project.ts index ca5e12999ca..544d6e0e8a0 100644 --- a/src/lib/schematics/utils/get-project.ts +++ b/src/lib/schematics/utils/get-project.ts @@ -15,7 +15,7 @@ import {WorkspaceProject, WorkspaceSchema} from '@schematics/angular/utility/con export function getProjectFromWorkspace(workspace: WorkspaceSchema, projectName?: string): WorkspaceProject { - let project = workspace.projects[projectName || workspace.defaultProject]; + const project = workspace.projects[projectName || workspace.defaultProject!]; if (!project) { throw new Error(`Could not find project in workspace: ${projectName}`); diff --git a/tslint.json b/tslint.json index 6d8f8647fe6..59076ad3c6e 100644 --- a/tslint.json +++ b/tslint.json @@ -134,10 +134,7 @@ "exclude": [ // Exclude schematic template files and test cases that can't be linted. "src/lib/schematics/**/files/**/*", - "src/lib/schematics/update/test-cases/**/*", - // TODO(paul) re-renable specs once the devkit schematics properly work with Bazel and we - // can remove the `xit` calls. - "src/lib/schematics/**/*.spec.ts" + "src/lib/schematics/update/test-cases/**/*" ] } }