mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: prepare schematics for v8 (#14667)
* Prepares the schematics for V8 * Dynamically resolves the test cases so that we don't need to hardcode them for each version
This commit is contained in:
committed by
Andrew Seguin
parent
0d7258b4e2
commit
bb419d3fb4
@@ -11,6 +11,11 @@
|
||||
"description": "Updates the Angular CDK to v7",
|
||||
"factory": "./ng-update/index#updateToV7"
|
||||
},
|
||||
"migration-v8": {
|
||||
"version": "8",
|
||||
"description": "Updates the Angular CDK to v8",
|
||||
"factory": "./ng-update/index#updateToV8"
|
||||
},
|
||||
"ng-post-update": {
|
||||
"description": "Prints out results after ng-update.",
|
||||
"factory": "./ng-update/index#postUpdate",
|
||||
|
||||
@@ -35,6 +35,11 @@ export function updateToV7(): Rule {
|
||||
return createUpgradeRule(TargetVersion.V7, tslintUpgradeConfig);
|
||||
}
|
||||
|
||||
/** Entry point for the migration schematics with target of Angular Material 8.0.0 */
|
||||
export function updateToV8(): Rule {
|
||||
return createUpgradeRule(TargetVersion.V8, tslintUpgradeConfig);
|
||||
}
|
||||
|
||||
/** Post-update schematic to be called when update is finished. */
|
||||
export function postUpdate(): Rule {
|
||||
return () => {
|
||||
|
||||
@@ -10,4 +10,14 @@
|
||||
export enum TargetVersion {
|
||||
V6,
|
||||
V7,
|
||||
V8,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all versions that are supported by "ng update". The versions are determined
|
||||
* based on the "TargetVersion" enum.
|
||||
*/
|
||||
export function getAllVersionNames(): string[] {
|
||||
return Object.keys(TargetVersion)
|
||||
.filter(enumValue => typeof TargetVersion[enumValue] === 'number');
|
||||
}
|
||||
|
||||
@@ -1,2 +1,18 @@
|
||||
import {defineJasmineTestCases, findBazelVersionTestCases} from '@angular/cdk/schematics/testing';
|
||||
import {getAllVersionNames} from '../target-version';
|
||||
|
||||
/** Path to the schematic collection that includes the migrations. */
|
||||
export const migrationCollection = require.resolve('../../migration.json');
|
||||
|
||||
describe('CDK upgrade test cases', () => {
|
||||
|
||||
const versionNames = getAllVersionNames().map(versionName => versionName.toLowerCase());
|
||||
const testCasesMap = findBazelVersionTestCases(
|
||||
'angular_material/src/cdk/schematics/ng-update/test-cases');
|
||||
|
||||
// Setup the test cases for each target version. The test cases will be automatically
|
||||
// detected through Bazel's runfiles manifest.
|
||||
versionNames.forEach(version => describe(`${version} update`, () => {
|
||||
defineJasmineTestCases(version, migrationCollection, testCasesMap.get(version));
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -4,9 +4,8 @@ import {runTestCases} from '../../../testing';
|
||||
describe('v6 method call checks', () => {
|
||||
|
||||
it('should properly report invalid method calls', async () => {
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection, {
|
||||
'method-call-checks': require.resolve('./method-call-checks_input.ts')
|
||||
});
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection,
|
||||
[require.resolve('./method-call-checks_input.ts')]);
|
||||
|
||||
expect(logOutput)
|
||||
.toMatch(/:15.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/);
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
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;
|
||||
let cleanupTestApp: () => void;
|
||||
|
||||
beforeAll(async () => {
|
||||
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
|
||||
inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
|
||||
return inputs;
|
||||
}, {} as {[name: string]: string});
|
||||
|
||||
const {tempPath, removeTempDir} =
|
||||
await runTestCases('migration-v6', migrationCollection, testCaseInputs);
|
||||
|
||||
testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
|
||||
cleanupTestApp = removeTempDir;
|
||||
});
|
||||
|
||||
afterAll(() => cleanupTestApp());
|
||||
|
||||
// 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
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;
|
||||
let cleanupTestApp: () => void;
|
||||
|
||||
beforeAll(async () => {
|
||||
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
|
||||
inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
|
||||
return inputs;
|
||||
}, {} as {[name: string]: string});
|
||||
|
||||
const {tempPath, removeTempDir} =
|
||||
await runTestCases('migration-v7', migrationCollection, testCaseInputs);
|
||||
|
||||
testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
|
||||
cleanupTestApp = removeTempDir;
|
||||
});
|
||||
|
||||
afterAll(() => cleanupTestApp());
|
||||
|
||||
// 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,10 +14,11 @@ targets a specific Angular CDK or Angular Material version.
|
||||
As of right now, we have two migration entry-points that handle the breaking changes for the
|
||||
given target version:
|
||||
|
||||
| Target Version | Description |
|
||||
|----------------|-------------|
|
||||
| Target Version | Description |
|
||||
|----------------|------------------------|
|
||||
| V6 | Upgrade from any version to v6.0.0 |
|
||||
| V7 | Upgrade from any version to v7.0.0 |
|
||||
| V8 | Upgrade from any version to v8.0.0 |
|
||||
|
||||
Note that the migrations run _in order_ if multiple versions are transitively targeted. For
|
||||
example, consider an application which uses Angular Material v5.0.0. In case the developer runs
|
||||
|
||||
@@ -6,12 +6,15 @@ ts_library(
|
||||
name = "testing",
|
||||
module_name = "@angular/cdk/schematics/testing",
|
||||
srcs = glob(["**/*.ts"]),
|
||||
tsconfig = "tsconfig.json",
|
||||
deps = [
|
||||
"@matdeps//@angular-devkit/core",
|
||||
"@matdeps//@angular-devkit/schematics",
|
||||
"@matdeps//@schematics/angular",
|
||||
"@matdeps//@types/node",
|
||||
"@matdeps//@types/fs-extra",
|
||||
"@matdeps//@types/jasmine",
|
||||
"@matdeps//@types/glob",
|
||||
"@matdeps//fs-extra",
|
||||
"@matdeps//rxjs",
|
||||
],
|
||||
|
||||
@@ -11,9 +11,16 @@ 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 {mkdirpSync, readFileSync, writeFileSync, removeSync} from 'fs-extra';
|
||||
import {dirname, join} from 'path';
|
||||
import {sync as globSync} from 'glob';
|
||||
import {dirname, join, basename, relative, sep} from 'path';
|
||||
import {createTestApp, runPostScheduledTasks} from '../testing';
|
||||
|
||||
/** Suffix that indicates whether a given file is a test case input. */
|
||||
const TEST_CASE_INPUT_SUFFIX = '_input.ts';
|
||||
|
||||
/** Suffix that indicates whether a given file is an expected output of a test case. */
|
||||
const TEST_CASE_OUTPUT_SUFFIX = '_expected_output.ts';
|
||||
|
||||
/** Reads the UTF8 content of the specified file. Normalizes the path and ensures that */
|
||||
export function readFileContent(filePath: string): string {
|
||||
return readFileSync(filePath, 'utf8');
|
||||
@@ -38,10 +45,9 @@ export function createFileSystemTestApp(runner: SchematicTestRunner) {
|
||||
}
|
||||
|
||||
export async function runTestCases(migrationName: string, collectionPath: string,
|
||||
inputs: {[name: string]: string}) {
|
||||
inputFiles: string[]) {
|
||||
|
||||
const runner = new SchematicTestRunner('schematics', collectionPath);
|
||||
const inputNames = Object.keys(inputs);
|
||||
const initialWorkingDir = process.cwd();
|
||||
|
||||
let logOutput = '';
|
||||
@@ -51,11 +57,12 @@ export async function runTestCases(migrationName: string, collectionPath: string
|
||||
|
||||
// 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`);
|
||||
inputFiles.forEach(inputFilePath => {
|
||||
const inputTestName = basename(inputFilePath);
|
||||
const tempInputPath = join(tempPath, `projects/cdk-testing/src/test-cases/${inputTestName}.ts`);
|
||||
|
||||
mkdirpSync(dirname(tempInputPath));
|
||||
writeFileSync(tempInputPath, readFileContent(inputs[inputName]));
|
||||
writeFileSync(tempInputPath, readFileContent(inputFilePath));
|
||||
});
|
||||
|
||||
runner.runSchematic(migrationName, {}, appTree);
|
||||
@@ -73,3 +80,87 @@ export async function runTestCases(migrationName: string, collectionPath: string
|
||||
|
||||
return {tempPath, logOutput, removeTempDir};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all test cases for specified path using Bazel's runfile manifest. Note that we
|
||||
* cannot just use "glob" since the test case files are not copied to the Bazel bin directory
|
||||
* and are just runfiles.
|
||||
*/
|
||||
export function findBazelVersionTestCases(basePath: string) {
|
||||
const testCasesMap = new Map<string, string[]>();
|
||||
const manifestPath = process.env['RUNFILES_MANIFEST_FILE']!;
|
||||
const runfilesDir = process.env['RUNFILES'];
|
||||
|
||||
// In case we are not on Windows where runfiles are symlinked, we just find all
|
||||
// test case files by using "glob" and store them in our result map.
|
||||
if (!manifestPath) {
|
||||
const runfilesBaseDir = join(runfilesDir, basePath);
|
||||
const inputFiles = globSync(`**/*${TEST_CASE_INPUT_SUFFIX}`, {cwd: runfilesBaseDir});
|
||||
|
||||
inputFiles.forEach(inputFile => {
|
||||
// The target version of an input file will be determined from the first
|
||||
// path segment. (e.g. "v6/my_rule_input.ts" will be for "v6")
|
||||
const targetVersion = inputFile.split(sep)[0];
|
||||
const resolvedInputPath = join(runfilesBaseDir, inputFile);
|
||||
|
||||
testCasesMap.set(targetVersion,
|
||||
(testCasesMap.get(targetVersion) || []).concat(resolvedInputPath));
|
||||
});
|
||||
|
||||
return testCasesMap;
|
||||
}
|
||||
|
||||
// In case runfiles are not symlinked (e.g. on Windows), we resolve all test case files using
|
||||
// the Bazel runfiles manifest. Read more about the manifest here: https://git.io/fhIZE
|
||||
readFileSync(manifestPath, 'utf8').split('\n').forEach(line => {
|
||||
const [runfilePath, realPath] = line.split(' ');
|
||||
|
||||
// In case the mapped runfile starts with the specified base path and ends with "_input.ts",
|
||||
// we store it in our result map because we assume that this is a test case.
|
||||
if (runfilePath.startsWith(basePath) && runfilePath.endsWith(TEST_CASE_INPUT_SUFFIX)) {
|
||||
// The target version of an input file will be determined from the first
|
||||
// path segment. (e.g. "v6/my_rule_input.ts" will be for "v6")
|
||||
const targetVersion = relative(basePath, runfilePath).split(sep)[0];
|
||||
testCasesMap.set(targetVersion, (testCasesMap.get(targetVersion) || []).concat(realPath));
|
||||
}
|
||||
});
|
||||
|
||||
return testCasesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the specified test cases using Jasmine by creating the appropriate jasmine
|
||||
* spec definitions. This should be used within a "describe" jasmine closure.
|
||||
*/
|
||||
export function defineJasmineTestCases(versionName: string, collectionFile: string,
|
||||
inputFiles: string[] | undefined) {
|
||||
// No test cases for the given version are available. Skip setting up tests for that
|
||||
// version.
|
||||
if (!inputFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
let testCasesOutputPath: string;
|
||||
let cleanupTestApp: () => void;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {tempPath, removeTempDir} =
|
||||
await runTestCases(`migration-${versionName}`, collectionFile, inputFiles);
|
||||
|
||||
testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
|
||||
cleanupTestApp = removeTempDir;
|
||||
});
|
||||
|
||||
afterAll(() => cleanupTestApp());
|
||||
|
||||
// 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.
|
||||
inputFiles.forEach(inputFile => {
|
||||
const inputTestName = basename(inputFile);
|
||||
|
||||
it(`should apply update schematics to test case: ${inputTestName}`, () => {
|
||||
expect(readFileContent(join(testCasesOutputPath, `${inputTestName}.ts`)))
|
||||
.toBe(readFileContent(inputFile.replace(TEST_CASE_INPUT_SUFFIX, TEST_CASE_OUTPUT_SUFFIX)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es2015"],
|
||||
"types": ["node", "jasmine", "glob"]
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,18 @@
|
||||
/** Path to the schematic collection that includes the Angular Material migrations. */
|
||||
import {defineJasmineTestCases, findBazelVersionTestCases} from '@angular/cdk/schematics/testing';
|
||||
import {getAllVersionNames} from '@angular/cdk/schematics';
|
||||
|
||||
/** Path to the schematic collection that includes the migrations. */
|
||||
export const migrationCollection = require.resolve('../../migration.json');
|
||||
|
||||
describe('Material upgrade test cases', () => {
|
||||
|
||||
const versionNames = getAllVersionNames().map(versionName => versionName.toLowerCase());
|
||||
const testCasesMap = findBazelVersionTestCases(
|
||||
'angular_material/src/lib/schematics/ng-update/test-cases');
|
||||
|
||||
// Setup the test cases for each target version. The test cases will be automatically
|
||||
// detected through Bazel's runfiles manifest.
|
||||
versionNames.forEach(version => describe(`${version} update`, () => {
|
||||
defineJasmineTestCases(version, migrationCollection, testCasesMap.get(version));
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -4,9 +4,8 @@ import {runTestCases} from '@angular/cdk/schematics/testing';
|
||||
describe('constructor checks', () => {
|
||||
|
||||
it('should properly report invalid constructor expression signatures', async () => {
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection, {
|
||||
'constructor-checks': require.resolve('./constructor-checks_input.ts')
|
||||
});
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection,
|
||||
[require.resolve('./constructor-checks_input.ts')]);
|
||||
|
||||
expect(logOutput).toMatch(/:22.*Found "NativeDateAdapter"/,
|
||||
'Expected the constructor checks to report if an argument is not assignable.');
|
||||
|
||||
@@ -4,9 +4,8 @@ import {migrationCollection} from '../index.spec';
|
||||
describe('v6 import misc checks', () => {
|
||||
|
||||
it('should report imports for deleted animation constants', async () => {
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection, {
|
||||
'import-checks': require.resolve('./import-checks_input.ts')
|
||||
});
|
||||
const {logOutput, removeTempDir} = await runTestCases('migration-v6', migrationCollection,
|
||||
[require.resolve('./import-checks_input.ts')]);
|
||||
|
||||
expect(logOutput).toMatch(/Found deprecated symbol "SHOW_ANIMATION"/);
|
||||
expect(logOutput).toMatch(/Found deprecated symbol "HIDE_ANIMATION"/);
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import {join} from 'path';
|
||||
import {readFileContent, runTestCases} from '@angular/cdk/schematics/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/css-selectors',
|
||||
'v6/element-selectors',
|
||||
'v6/input-names',
|
||||
'v6/output-names',
|
||||
'v6/property-names',
|
||||
];
|
||||
|
||||
let testCasesOutputPath: string;
|
||||
let cleanupTestApp: () => void;
|
||||
|
||||
beforeAll(async () => {
|
||||
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
|
||||
inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
|
||||
return inputs;
|
||||
}, {} as {[name: string]: string});
|
||||
|
||||
const {tempPath, removeTempDir} =
|
||||
await runTestCases('migration-v6', migrationCollection, testCaseInputs);
|
||||
|
||||
testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
|
||||
cleanupTestApp = removeTempDir;
|
||||
});
|
||||
|
||||
afterAll(() => cleanupTestApp());
|
||||
|
||||
// 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import {join} from 'path';
|
||||
import {readFileContent, runTestCases} from '@angular/cdk/schematics/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',
|
||||
'v7/ripple-speed-factor',
|
||||
];
|
||||
|
||||
let testCasesOutputPath: string;
|
||||
let cleanupTestApp: () => void;
|
||||
|
||||
beforeAll(async () => {
|
||||
const testCaseInputs = testCases.reduce((inputs, testCaseName) => {
|
||||
inputs[testCaseName] = require.resolve(`./${testCaseName}_input.ts`);
|
||||
return inputs;
|
||||
}, {} as {[name: string]: string});
|
||||
|
||||
const {tempPath, removeTempDir} =
|
||||
await runTestCases('migration-v7', migrationCollection, testCaseInputs);
|
||||
|
||||
testCasesOutputPath = join(tempPath, 'projects/cdk-testing/src/test-cases/');
|
||||
cleanupTestApp = removeTempDir;
|
||||
});
|
||||
|
||||
afterAll(() => cleanupTestApp());
|
||||
|
||||
// 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user