diff --git a/src/cdk/schematics/BUILD.bazel b/src/cdk/schematics/BUILD.bazel
index fbbd6da4210..db686759070 100644
--- a/src/cdk/schematics/BUILD.bazel
+++ b/src/cdk/schematics/BUILD.bazel
@@ -16,14 +16,20 @@ filegroup(
ts_library(
name = "schematics",
module_name = "@angular/cdk/schematics",
- srcs = glob(["**/*.ts"], exclude=["**/files/**/*.ts", "**/*.spec.ts"]),
+ srcs = glob(["**/*.ts"], exclude=[
+ "**/files/**/*.ts",
+ "**/*.spec.ts",
+ "ng-update/test-cases/**/*",
+ ]),
tsconfig = ":tsconfig.json",
deps = [
"@npm//@schematics/angular",
"@npm//@angular-devkit/schematics",
- # TODO(devversion): Only include jasmine for test sources (See: tsconfig types).
+ # TODO(devversion): Only include jasmine for test sources (See: tsconfig types).
"@npm//@types/jasmine",
"@npm//@types/node",
+ # TODO(devversion): Similarly to "jasmine", we need to extract these into testing only.
+ "@npm//fs-extra",
"@npm//glob",
"@npm//parse5",
"@npm//rxjs",
@@ -45,7 +51,7 @@ npm_package(
jasmine_node_test(
name = "unit_tests",
srcs = [":schematics_test_sources"],
- data = [":schematics_assets"],
+ data = [":schematics_assets", ":schematics_test_cases"],
)
ts_library(
@@ -64,3 +70,12 @@ ts_library(
tsconfig = ":tsconfig.json",
testonly = True,
)
+
+filegroup(
+ name = "schematics_test_cases",
+ srcs = glob([
+ "ng-update/test-cases/**/*_input.ts",
+ "ng-update/test-cases/**/*_expected_output.ts"
+ ]),
+ testonly = True,
+)
diff --git a/src/cdk/schematics/ng-update/test-cases/index.spec.ts b/src/cdk/schematics/ng-update/test-cases/index.spec.ts
new file mode 100644
index 00000000000..45ca97c2664
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/index.spec.ts
@@ -0,0 +1,2 @@
+/** Path to the schematic collection that includes the migrations. */
+export const migrationCollection = require.resolve('../../migration.json');
diff --git a/src/cdk/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts b/src/cdk/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts
new file mode 100644
index 00000000000..37be49ece93
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts
@@ -0,0 +1,16 @@
+import {migrationCollection} from '../index.spec';
+import {runTestCases} from '../../../testing';
+
+describe('v6 method call checks', () => {
+
+ it('should properly report invalid method calls', async () => {
+ const {logOutput} = await runTestCases('migration-v6', migrationCollection, {
+ 'method-call-checks': require.resolve('./method-call-checks_input.ts')
+ });
+
+ expect(logOutput)
+ .toMatch(/\[15,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/);
+ expect(logOutput)
+ .toMatch(/\[16,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/);
+ });
+});
diff --git a/src/lib/schematics/ng-update/test-cases/misc/method-call-checks_input.ts b/src/cdk/schematics/ng-update/test-cases/misc/method-call-checks_input.ts
similarity index 99%
rename from src/lib/schematics/ng-update/test-cases/misc/method-call-checks_input.ts
rename to src/cdk/schematics/ng-update/test-cases/misc/method-call-checks_input.ts
index bf41d919e30..8008bb22b0b 100644
--- a/src/lib/schematics/ng-update/test-cases/misc/method-call-checks_input.ts
+++ b/src/cdk/schematics/ng-update/test-cases/misc/method-call-checks_input.ts
@@ -15,4 +15,4 @@ class A implements AfterViewInit {
this.focusMonitor.monitor(this.elementRef.nativeElement, this.renderer, true);
this.self.a.monitor(this.elementRef.nativeElement, this.renderer, true);
}
-}
+}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v6-test-cases.spec.ts b/src/cdk/schematics/ng-update/test-cases/v6-test-cases.spec.ts
new file mode 100644
index 00000000000..5d0a68be683
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6-test-cases.spec.ts
@@ -0,0 +1,43 @@
+import {join} from 'path';
+import {readFileContent, runTestCases} from '../../testing';
+import {migrationCollection} from './index.spec';
+
+describe('v6 upgrade test cases', () => {
+
+ /**
+ * Name of test cases that will be used to verify that update schematics properly update
+ * a developers application.
+ */
+ const testCases = [
+ 'v6/attribute-selectors',
+ 'v6/class-names',
+ 'v6/input-names',
+ 'v6/property-names',
+ ];
+
+ let testCasesOutputPath: string;
+
+ beforeAll(async () => {
+ const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
+ inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
+ return inputs;
+ }, {} as {[name: string]: string});
+
+ const {tempPath} = await runTestCases('migration-v6', migrationCollection, testCaseInputs);
+
+ testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
+ });
+
+ // Iterates through every test case directory and generates a jasmine test block that will
+ // verify that the update schematics properly updated the test input to the expected output.
+ testCases.forEach(testCaseName => {
+ const expectedOutputPath = require.resolve(`./${testCaseName}_expected_output.ts`);
+
+ it(`should apply update schematics to test case: ${testCaseName}`, () => {
+ expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`)))
+ .toBe(readFileContent(expectedOutputPath));
+ });
+ });
+});
+
+
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_expected_output.ts b/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_expected_output.ts
new file mode 100644
index 00000000000..f162584e957
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_expected_output.ts
@@ -0,0 +1,34 @@
+import {Component} from '@angular/core';
+import {By} from '@angular/platform-browser';
+
+const a = By.css('[cdkPortalOutlet]');
+const b = By.css('[cdkPortalOutlet]');
+
+// These should not change because we only update string literals that are
+// inside of a call expression.
+const c = 'cdkPortalHost';
+const d = 'portalHost';
+
+@Component({
+ template: `
+
+
+ `,
+ styles: [
+ '[cdkPortalOutlet] {background: red}',
+ 'div[cdkPortalOutlet] {color: blue}'
+ ]
+})
+class E {}
+
+@Component({
+ template: `
+
+
+ `,
+ styles: [
+ '[cdkPortalOutlet] {background: red}',
+ 'div[cdkPortalOutlet] {color: blue}'
+ ]
+})
+class F {}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_input.ts b/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_input.ts
new file mode 100644
index 00000000000..2ba661c3553
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/attribute-selectors_input.ts
@@ -0,0 +1,34 @@
+import {Component} from '@angular/core';
+import {By} from '@angular/platform-browser';
+
+const a = By.css('[cdkPortalHost]');
+const b = By.css('[portalHost]');
+
+// These should not change because we only update string literals that are
+// inside of a call expression.
+const c = 'cdkPortalHost';
+const d = 'portalHost';
+
+@Component({
+ template: `
+
+
+ `,
+ styles: [
+ '[cdkPortalHost] {background: red}',
+ 'div[cdkPortalHost] {color: blue}'
+ ]
+})
+class E {}
+
+@Component({
+ template: `
+
+
+ `,
+ styles: [
+ '[portalHost] {background: red}',
+ 'div[portalHost] {color: blue}'
+ ]
+})
+class F {}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/class-names_expected_output.ts b/src/cdk/schematics/ng-update/test-cases/v6/class-names_expected_output.ts
new file mode 100644
index 00000000000..0ed0327d3d5
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/class-names_expected_output.ts
@@ -0,0 +1,8 @@
+import {CdkConnectedOverlay, CdkOverlayOrigin} from '@angular/cdk/overlay';
+import {CdkObserveContent} from '@angular/cdk/observers';
+import {CdkTrapFocus} from '@angular/cdk/a11y';
+
+const a = new CdkConnectedOverlay();
+const b = new CdkOverlayOrigin();
+const c = new CdkObserveContent();
+const d = new CdkTrapFocus();
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/class-names_input.ts b/src/cdk/schematics/ng-update/test-cases/v6/class-names_input.ts
new file mode 100644
index 00000000000..dc2fc838124
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/class-names_input.ts
@@ -0,0 +1,8 @@
+import {ConnectedOverlayDirective, OverlayOrigin} from '@angular/cdk/overlay';
+import {ObserveContent} from '@angular/cdk/observers';
+import {FocusTrapDirective} from '@angular/cdk/a11y';
+
+const a = new ConnectedOverlayDirective();
+const b = new OverlayOrigin();
+const c = new ObserveContent();
+const d = new FocusTrapDirective();
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/input-names_expected_output.ts b/src/cdk/schematics/ng-update/test-cases/v6/input-names_expected_output.ts
new file mode 100644
index 00000000000..54168124324
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/input-names_expected_output.ts
@@ -0,0 +1,21 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+ `
+})
+class A {}
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/input-names_input.ts b/src/cdk/schematics/ng-update/test-cases/v6/input-names_input.ts
new file mode 100644
index 00000000000..eb66045b207
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/input-names_input.ts
@@ -0,0 +1,21 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+ `
+})
+class A {}
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/property-names_expected_output.ts b/src/cdk/schematics/ng-update/test-cases/v6/property-names_expected_output.ts
new file mode 100644
index 00000000000..623778a952d
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/property-names_expected_output.ts
@@ -0,0 +1,64 @@
+class CdkConnectedOverlay {
+ _deprecatedOrigin: any;
+ _deprecatedPositions: any;
+ _deprecatedOffsetX: any;
+ _deprecatedOffsetY: any;
+ _deprecatedWidth: any;
+ _deprecatedHeight: any;
+ _deprecatedMinWidth: any;
+ _deprecatedMinHeight: any;
+ _deprecatedBackdropClass: any;
+ _deprecatedScrollStrategy: any;
+ _deprecatedOpen: any;
+ _deprecatedHasBackdrop: any;
+}
+
+class CdkPortalOutlet {
+ _deprecatedPortal: any;
+ _deprecatedPortalHost: any;
+}
+
+class A {
+ self = {me: this};
+
+ constructor(private a: CdkConnectedOverlay) {}
+
+ onAngularClick() {
+ this.a.origin = '1';
+ this.a.positions = '2';
+ this.a.offsetX = '3';
+ this.a.offsetY = '4';
+ this.a.height = '5';
+
+ console.log(this.a.width || 10);
+ console.log(this.a.minWidth || this.a.minHeight);
+
+ this.self.me.a.backdropClass = ['a', 'b', 'c'];
+
+ const x = ({test: true} || this.a);
+
+ if (this.isConnectedOverlay(x)) {
+ x.scrollStrategy = 'myScrollStrategy';
+ x.open = false;
+ x.hasBackdrop = true;
+ }
+ }
+
+ isConnectedOverlay(val: any): val is CdkConnectedOverlay {
+ return val instanceof CdkConnectedOverlay;
+ }
+}
+
+class B {
+ self = {me: this};
+
+ constructor(protected a: CdkPortalOutlet) {}
+
+ onClick() {
+ this.a.portal = this.a.portal = 'myNewPortal';
+
+ if (this.self.me.a) {
+ console.log(this.a.portal || this.self.me.a.portal);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v6/property-names_input.ts b/src/cdk/schematics/ng-update/test-cases/v6/property-names_input.ts
new file mode 100644
index 00000000000..6bfd787a2eb
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v6/property-names_input.ts
@@ -0,0 +1,64 @@
+class CdkConnectedOverlay {
+ _deprecatedOrigin: any;
+ _deprecatedPositions: any;
+ _deprecatedOffsetX: any;
+ _deprecatedOffsetY: any;
+ _deprecatedWidth: any;
+ _deprecatedHeight: any;
+ _deprecatedMinWidth: any;
+ _deprecatedMinHeight: any;
+ _deprecatedBackdropClass: any;
+ _deprecatedScrollStrategy: any;
+ _deprecatedOpen: any;
+ _deprecatedHasBackdrop: any;
+}
+
+class CdkPortalOutlet {
+ _deprecatedPortal: any;
+ _deprecatedPortalHost: any;
+}
+
+class A {
+ self = {me: this};
+
+ constructor(private a: CdkConnectedOverlay) {}
+
+ onAngularClick() {
+ this.a._deprecatedOrigin = '1';
+ this.a._deprecatedPositions = '2';
+ this.a._deprecatedOffsetX = '3';
+ this.a._deprecatedOffsetY = '4';
+ this.a._deprecatedHeight = '5';
+
+ console.log(this.a._deprecatedWidth || 10);
+ console.log(this.a._deprecatedMinWidth || this.a._deprecatedMinHeight);
+
+ this.self.me.a._deprecatedBackdropClass = ['a', 'b', 'c'];
+
+ const x = ({test: true} || this.a);
+
+ if (this.isConnectedOverlay(x)) {
+ x._deprecatedScrollStrategy = 'myScrollStrategy';
+ x._deprecatedOpen = false;
+ x._deprecatedHasBackdrop = true;
+ }
+ }
+
+ isConnectedOverlay(val: any): val is CdkConnectedOverlay {
+ return val instanceof CdkConnectedOverlay;
+ }
+}
+
+class B {
+ self = {me: this};
+
+ constructor(protected a: CdkPortalOutlet) {}
+
+ onClick() {
+ this.a._deprecatedPortal = this.a._deprecatedPortalHost = 'myNewPortal';
+
+ if (this.self.me.a) {
+ console.log(this.a._deprecatedPortalHost || this.self.me.a._deprecatedPortal);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v7-test-cases.spec.ts b/src/cdk/schematics/ng-update/test-cases/v7-test-cases.spec.ts
new file mode 100644
index 00000000000..ab4d02b8dd5
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v7-test-cases.spec.ts
@@ -0,0 +1,39 @@
+import {join} from 'path';
+import {readFileContent, runTestCases} from '../../testing';
+import {migrationCollection} from './index.spec';
+
+describe('v7 upgrade test cases', () => {
+
+ /**
+ * Name of test cases that will be used to verify that update schematics properly update
+ * a developers application.
+ */
+ const testCases = [
+ 'v7/property-names',
+ ];
+
+ let testCasesOutputPath: string;
+
+ beforeAll(async () => {
+ const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
+ inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
+ return inputs;
+ }, {} as {[name: string]: string});
+
+ const {tempPath} = await runTestCases('migration-v7', migrationCollection, testCaseInputs);
+
+ testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
+ });
+
+ // Iterates through every test case directory and generates a jasmine test block that will
+ // verify that the update schematics properly updated the test input to the expected output.
+ testCases.forEach(testCaseName => {
+ const expectedOutputPath = require.resolve(`./${testCaseName}_expected_output.ts`);
+
+ it(`should apply update schematics to test case: ${testCaseName}`, () => {
+ expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`)))
+ .toBe(readFileContent(expectedOutputPath));
+ });
+ });
+});
+
diff --git a/src/cdk/schematics/ng-update/test-cases/v7/property-names_expected_output.ts b/src/cdk/schematics/ng-update/test-cases/v7/property-names_expected_output.ts
new file mode 100644
index 00000000000..fb4c6314fb1
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v7/property-names_expected_output.ts
@@ -0,0 +1,28 @@
+import {EventEmitter, OnInit} from '@angular/core';
+
+class SelectionModel {
+ onChange = new EventEmitter();
+}
+
+class CdkConnectedOverlay {
+ flexibleDiemsions: boolean;
+}
+
+/* Actual test case using the previously defined definitions. */
+
+class A implements OnInit {
+ self = {me: this};
+
+ constructor(private a: SelectionModel, private b: CdkConnectedOverlay) {}
+
+ ngOnInit() {
+ this.a.changed.subscribe(() => console.log('Changed'));
+ this.self.me.a.changed.subscribe(() => console.log('Changed 2'));
+
+ if (this.b.flexibleDimensions) {
+ console.log(this.b.flexibleDimensions ? 'true' : 'false');
+ }
+
+ const _state = this.self.me.b.flexibleDimensions.toString() || 'not-defined';
+ }
+}
\ No newline at end of file
diff --git a/src/cdk/schematics/ng-update/test-cases/v7/property-names_input.ts b/src/cdk/schematics/ng-update/test-cases/v7/property-names_input.ts
new file mode 100644
index 00000000000..c3dfdc3781f
--- /dev/null
+++ b/src/cdk/schematics/ng-update/test-cases/v7/property-names_input.ts
@@ -0,0 +1,28 @@
+import {EventEmitter, OnInit} from '@angular/core';
+
+class SelectionModel {
+ onChange = new EventEmitter();
+}
+
+class CdkConnectedOverlay {
+ flexibleDiemsions: boolean;
+}
+
+/* Actual test case using the previously defined definitions. */
+
+class A implements OnInit {
+ self = {me: this};
+
+ constructor(private a: SelectionModel, private b: CdkConnectedOverlay) {}
+
+ ngOnInit() {
+ this.a.onChange.subscribe(() => console.log('Changed'));
+ this.self.me.a.onChange.subscribe(() => console.log('Changed 2'));
+
+ if (this.b.flexibleDiemsions) {
+ console.log(this.b.flexibleDiemsions ? 'true' : 'false');
+ }
+
+ const _state = this.self.me.b.flexibleDiemsions.toString() || 'not-defined';
+ }
+}
\ No newline at end of file
diff --git a/src/cdk/schematics/testing/index.ts b/src/cdk/schematics/testing/index.ts
index 1141e3fde64..900f9c06084 100644
--- a/src/cdk/schematics/testing/index.ts
+++ b/src/cdk/schematics/testing/index.ts
@@ -8,3 +8,4 @@
export * from './post-scheduled-tasks';
export * from './test-app';
+export * from './test-case-setup';
diff --git a/src/cdk/schematics/testing/test-app.ts b/src/cdk/schematics/testing/test-app.ts
index b1b87bfd596..8bc1399a5da 100644
--- a/src/cdk/schematics/testing/test-app.ts
+++ b/src/cdk/schematics/testing/test-app.ts
@@ -17,5 +17,5 @@ export function createTestApp(runner: SchematicTestRunner, appOptions = {}): Uni
});
return runner.runExternalSchematic('@schematics/angular', 'application',
- {...appOptions, name: 'material'}, workspaceTree);
+ {name: 'material', ...appOptions}, workspaceTree);
}
diff --git a/src/cdk/schematics/testing/test-case-setup.ts b/src/cdk/schematics/testing/test-case-setup.ts
new file mode 100644
index 00000000000..9099d325d1a
--- /dev/null
+++ b/src/cdk/schematics/testing/test-case-setup.ts
@@ -0,0 +1,75 @@
+/**
+ * @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 {getSystemPath, normalize} from '@angular-devkit/core';
+import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing';
+import * as virtualFs from '@angular-devkit/core/src/virtual-fs/host';
+import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
+import {readFileSync, writeFileSync, mkdirpSync} from 'fs-extra';
+import {join, dirname} from 'path';
+import {createTestApp, runPostScheduledTasks} from '../testing';
+
+/** Reads the UTF8 content of the specified file. Normalizes the path and ensures that */
+export function readFileContent(filePath: string): string {
+ return readFileSync(filePath, 'utf8');
+}
+
+/**
+ * Creates a test app schematic tree that will be copied over to a real filesystem location.
+ * This is necessary because TSLint is not able to read from the virtual filesystem tree.
+ */
+export function createFileSystemTestApp(runner: SchematicTestRunner) {
+ const tempFileSystemHost = new TempScopedNodeJsSyncHost();
+ const appTree = createTestApp(runner, {name: 'cdk-testing'});
+ const tempPath = getSystemPath(tempFileSystemHost.root);
+
+ // Since the TSLint fix task expects all files to be present on the real file system, we
+ // map every file in the app tree to a temporary location on the file system.
+ appTree.files.map(f => normalize(f)).forEach(f => {
+ tempFileSystemHost.sync.write(f, virtualFs.stringToFileBuffer(appTree.readContent(f)));
+ });
+
+ return {appTree, tempPath};
+}
+
+export async function runTestCases(migrationName: string, collectionPath: string,
+ inputs: {[name: string]: string}) {
+
+ const runner = new SchematicTestRunner('schematics', collectionPath);
+ const inputNames = Object.keys(inputs);
+ const initialWorkingDir = process.cwd();
+
+ let logOutput = '';
+ runner.logger.subscribe(entry => logOutput += entry.message);
+
+ const {appTree, tempPath} = createFileSystemTestApp(runner);
+
+ // Write each test-case input to the file-system. This is necessary because otherwise
+ // TSLint won't be able to pick up the test cases.
+ inputNames.forEach(inputName => {
+ const tempInputPath = join(tempPath, `projects/cdk-testing/src/test-cases/${inputName}.ts`);
+
+ mkdirpSync(dirname(tempInputPath));
+ writeFileSync(tempInputPath, readFileContent(inputs[inputName]));
+ });
+
+ runner.runSchematic(migrationName, {}, appTree);
+
+ // Switch to the new temporary directory because otherwise TSLint cannot read the files.
+ process.chdir(tempPath);
+
+ // Run the scheduled TSLint fix task from the update schematic. This task is responsible for
+ // identifying outdated code parts and performs the fixes. Since tasks won't run automatically
+ // within a `SchematicTestRunner`, we manually need to run the scheduled task.
+ await runPostScheduledTasks(runner, 'tslint-fix').toPromise();
+
+ // Switch back to the initial working directory.
+ process.chdir(initialWorkingDir);
+
+ return {tempPath, logOutput};
+}
diff --git a/src/cdk/schematics/tsconfig.json b/src/cdk/schematics/tsconfig.json
index 137ad9553d8..50dee289ddd 100644
--- a/src/cdk/schematics/tsconfig.json
+++ b/src/cdk/schematics/tsconfig.json
@@ -19,7 +19,8 @@
},
"exclude": [
"**/files/**/*",
- "**/*.spec.ts"
+ "**/*.spec.ts",
+ "ng-update/test-cases/**/*"
],
"bazelOptions": {
"suppressTsconfigOverrideWarnings": true
diff --git a/src/lib/schematics/BUILD.bazel b/src/lib/schematics/BUILD.bazel
index 061bc48922c..96bfc45107e 100644
--- a/src/lib/schematics/BUILD.bazel
+++ b/src/lib/schematics/BUILD.bazel
@@ -57,7 +57,6 @@ ts_library(
"@npm//@angular-devkit/schematics",
"@npm//@types/jasmine",
"@npm//@types/node",
- "@npm//fs-extra",
],
tsconfig = ":tsconfig.json",
testonly = True,
diff --git a/src/lib/schematics/ng-update/test-cases/index.spec.ts b/src/lib/schematics/ng-update/test-cases/index.spec.ts
index b2990c39d60..40ec043f89e 100644
--- a/src/lib/schematics/ng-update/test-cases/index.spec.ts
+++ b/src/lib/schematics/ng-update/test-cases/index.spec.ts
@@ -1,83 +1,2 @@
-import {getSystemPath, normalize} from '@angular-devkit/core';
-import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing';
-import * as virtualFs from '@angular-devkit/core/src/virtual-fs/host';
-import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
-import {readFileSync, writeFileSync, mkdirpSync} from 'fs-extra';
-import {join, dirname} from 'path';
-import {createTestApp, runPostScheduledTasks} from '@angular/cdk/schematics';
-
/** Path to the schematic collection that includes the Angular Material migrations. */
-const migrationCollection = require.resolve('../../migration.json');
-
-/** Module name suffix for data files of the `jasmine_node_test` Bazel rule. */
-const bazelModuleSuffix = 'angular_material/src/lib/schematics/ng-update/test-cases';
-
-/** Reads the UTF8 content of the specified file. Normalizes the path and ensures that */
-export function readFileContent(filePath: string): string {
- return readFileSync(filePath, 'utf8');
-}
-
-/**
- * Resolves the original file path of the specified file that has been to the `data` of the
- * jasmine_node_test Bazel rule.
- *
- * 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.
- */
-export function resolveBazelDataFile(filePath: string) {
- return require.resolve(`${bazelModuleSuffix}/${filePath}`);
-}
-
-/**
- * Creates a test app schematic tree that will be copied over to a real filesystem location.
- * This is necessary because TSLint is not able to read from the virtual filesystem tree.
- */
-export function createFileSystemTestApp(runner: SchematicTestRunner) {
- const tempFileSystemHost = new TempScopedNodeJsSyncHost();
- const appTree = createTestApp(runner);
- const tempPath = getSystemPath(tempFileSystemHost.root);
-
- // Since the TSLint fix task expects all files to be present on the real file system, we
- // map every file in the app tree to a temporary location on the file system.
- appTree.files.map(f => normalize(f)).forEach(f => {
- tempFileSystemHost.sync.write(f, virtualFs.stringToFileBuffer(appTree.readContent(f)));
- });
-
- return {appTree, tempPath};
-}
-
-export async function runTestCases(migrationName: string, inputs: {[name: string]: string}) {
- const runner = new SchematicTestRunner('schematics', migrationCollection);
- const inputNames = Object.keys(inputs);
- const initialWorkingDir = process.cwd();
-
- let logOutput = '';
- runner.logger.subscribe(entry => logOutput += entry.message);
-
- const {appTree, tempPath} = createFileSystemTestApp(runner);
-
- // Write each test-case input to the file-system. This is necessary because otherwise
- // TSLint won't be able to pick up the test cases.
- inputNames.forEach(inputName => {
- const tempInputPath = join(tempPath, `projects/material/src/test-cases/${inputName}.ts`);
-
- mkdirpSync(dirname(tempInputPath));
- writeFileSync(tempInputPath, readFileContent(inputs[inputName]));
- });
-
- runner.runSchematic(migrationName, {}, appTree);
-
- // Switch to the new temporary directory because otherwise TSLint cannot read the files.
- process.chdir(tempPath);
-
- // Run the scheduled TSLint fix task from the update schematic. This task is responsible for
- // identifying outdated code parts and performs the fixes. Since tasks won't run automatically
- // within a `SchematicTestRunner`, we manually need to run the scheduled task.
- await runPostScheduledTasks(runner, 'tslint-fix').toPromise();
-
- // Switch back to the initial working directory.
- process.chdir(initialWorkingDir);
-
- return {tempPath, logOutput};
-}
+export const migrationCollection = require.resolve('../../migration.json');
diff --git a/src/lib/schematics/ng-update/test-cases/misc/constructor-checks.spec.ts b/src/lib/schematics/ng-update/test-cases/misc/constructor-checks.spec.ts
index b702af39517..f71a602936b 100644
--- a/src/lib/schematics/ng-update/test-cases/misc/constructor-checks.spec.ts
+++ b/src/lib/schematics/ng-update/test-cases/misc/constructor-checks.spec.ts
@@ -1,10 +1,11 @@
-import {resolveBazelDataFile, runTestCases} from '../index.spec';
+import {migrationCollection} from '../index.spec';
+import {runTestCases} from '@angular/cdk/schematics';
describe('constructor checks', () => {
it('should properly report invalid constructor expression signatures', async () => {
- const {logOutput} = await runTestCases('migration-v6', {
- 'constructor-checks': resolveBazelDataFile(`misc/constructor-checks_input.ts`)
+ const {logOutput} = await runTestCases('migration-v6', migrationCollection, {
+ 'constructor-checks': require.resolve('./constructor-checks_input.ts')
});
expect(logOutput).toMatch(/\[22.*Found "NativeDateAdapter"/,
diff --git a/src/lib/schematics/ng-update/test-cases/misc/import-checks.spec.ts b/src/lib/schematics/ng-update/test-cases/misc/import-checks.spec.ts
index 25a8029700e..46d53b7502f 100644
--- a/src/lib/schematics/ng-update/test-cases/misc/import-checks.spec.ts
+++ b/src/lib/schematics/ng-update/test-cases/misc/import-checks.spec.ts
@@ -1,10 +1,11 @@
-import {resolveBazelDataFile, runTestCases} from '../index.spec';
+import {runTestCases} from '@angular/cdk/schematics';
+import {migrationCollection} from '../index.spec';
describe('v6 import misc checks', () => {
it('should report imports for deleted animation constants', async () => {
- const {logOutput} = await runTestCases('migration-v6', {
- 'import-checks': resolveBazelDataFile(`misc/import-checks_input.ts`)
+ const {logOutput} = await runTestCases('migration-v6', migrationCollection, {
+ 'import-checks': require.resolve('./import-checks_input.ts')
});
expect(logOutput).toMatch(/Found deprecated symbol "SHOW_ANIMATION"/);
diff --git a/src/lib/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts b/src/lib/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts
deleted file mode 100644
index 5a2f00f9842..00000000000
--- a/src/lib/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import {resolveBazelDataFile, runTestCases} from '../index.spec';
-
-describe('v6 method call checks', () => {
-
- it('should properly report invalid method calls', async () => {
- const {logOutput} = await runTestCases('migration-v6', {
- 'method-call-checks': resolveBazelDataFile(`misc/method-call-checks_input.ts`)
- });
-
- // TODO(devversion): Move this test case to the CDK and assert that this failure has been
- // reported by TSLint.
- expect(logOutput)
- .not.toMatch(/\[15,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/);
- expect(logOutput)
- .not.toMatch(/\[16,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/);
- });
-});
-
-
diff --git a/src/lib/schematics/ng-update/test-cases/v6-test-cases.spec.ts b/src/lib/schematics/ng-update/test-cases/v6-test-cases.spec.ts
index 0764e64e754..743773d0817 100644
--- a/src/lib/schematics/ng-update/test-cases/v6-test-cases.spec.ts
+++ b/src/lib/schematics/ng-update/test-cases/v6-test-cases.spec.ts
@@ -1,5 +1,6 @@
import {join} from 'path';
-import {readFileContent, resolveBazelDataFile, runTestCases} from './index.spec';
+import {readFileContent, runTestCases} from '@angular/cdk/schematics';
+import {migrationCollection} from './index.spec';
describe('v6 upgrade test cases', () => {
@@ -21,19 +22,19 @@ describe('v6 upgrade test cases', () => {
beforeAll(async () => {
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
- inputs[testCaseName] = resolveBazelDataFile(`${testCaseName}_input.ts`);
+ inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
return inputs;
- }, {});
+ }, {} as {[name: string]: string});
- const {tempPath} = await runTestCases('migration-v6', testCaseInputs);
+ const {tempPath} = await runTestCases('migration-v6', migrationCollection, testCaseInputs);
- testCasesOutputPath = join(tempPath, 'projects/material/src/test-cases/');
+ testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
});
// Iterates through every test case directory and generates a jasmine test block that will
// verify that the update schematics properly updated the test input to the expected output.
testCases.forEach(testCaseName => {
- const expectedOutputPath = resolveBazelDataFile(`${testCaseName}_expected_output.ts`);
+ const expectedOutputPath = require.resolve(`./${testCaseName}_expected_output.ts`);
it(`should apply update schematics to test case: ${testCaseName}`, () => {
expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`)))
diff --git a/src/lib/schematics/ng-update/test-cases/v7-test-cases.spec.ts b/src/lib/schematics/ng-update/test-cases/v7-test-cases.spec.ts
index bbdc6b5a577..fbc59cc52a1 100644
--- a/src/lib/schematics/ng-update/test-cases/v7-test-cases.spec.ts
+++ b/src/lib/schematics/ng-update/test-cases/v7-test-cases.spec.ts
@@ -1,5 +1,6 @@
import {join} from 'path';
-import {readFileContent, resolveBazelDataFile, runTestCases} from './index.spec';
+import {readFileContent, runTestCases} from '@angular/cdk/schematics';
+import {migrationCollection} from './index.spec';
describe('v7 upgrade test cases', () => {
@@ -16,19 +17,19 @@ describe('v7 upgrade test cases', () => {
beforeAll(async () => {
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
- inputs[testCaseName] = resolveBazelDataFile(`${testCaseName}_input.ts`);
+ inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
return inputs;
- }, {});
+ }, {} as {[name: string]: string});
- const {tempPath} = await runTestCases('migration-v7', testCaseInputs);
+ const {tempPath} = await runTestCases('migration-v7', migrationCollection, testCaseInputs);
- testCasesOutputPath = join(tempPath, 'projects/material/src/test-cases/');
+ testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
});
// Iterates through every test case directory and generates a jasmine test block that will
// verify that the update schematics properly updated the test input to the expected output.
testCases.forEach(testCaseName => {
- const expectedOutputPath = resolveBazelDataFile(`${testCaseName}_expected_output.ts`);
+ const expectedOutputPath = require.resolve(`./${testCaseName}_expected_output.ts`);
it(`should apply update schematics to test case: ${testCaseName}`, () => {
expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`)))
diff --git a/tslint.json b/tslint.json
index b6f248504e7..9b641777a4b 100644
--- a/tslint.json
+++ b/tslint.json
@@ -136,6 +136,7 @@
// Exclude schematic template files and test cases that can't be linted.
"src/lib/schematics/**/files/**/*",
"src/cdk/schematics/**/files/**/*",
+ "src/cdk/schematics/ng-update/test-cases/**/*",
"src/lib/schematics/ng-update/test-cases/**/*"
]
}