angular-cn/integration/ng_update_migrations/test.js

81 lines
3.1 KiB
JavaScript
Raw Normal View History

/**
* @license
* Copyright Google Inc. 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
*/
const path = require('path');
const fs = require('fs');
const child_process = require('child_process');
const glob = require('glob');
const chalk = require('chalk');
const diff = require('diff');
const projectDir = __dirname;
const cliBinPath = path.join(projectDir, 'node_modules/@angular/cli/bin/ng');
const expectationFiles = glob.sync('**/*_expected.ts', {cwd: projectDir});
refactor: enable ng update migrations for v10 (#36921) Enables the `ng update` migrations for v10. Status for individual migrations: **undecorated-classes-with-di**. This migration dealt exlusively with inherited constructors and cases where a derived component was undecorated. In those cases, the migration added `@Directive()` or copied the inherited decorator to the derived class. We don't need to run this migration again because ngtsc throws if constructor is inherited from an undecorated class. Also ngtsc will throw if a NgModule references an undecorated class in the declarations. ***undecorated-classes-with-decorated-fields*** This migration exclusively deals with undecorated classes that use Angular features but are not decorated. Angular features include the use of lifecycle hooks or class fields with Angular decorators, such as `@Input()`. We want to re-run this migration in v10 as we will disable the compatibility code in ngtsc that detects such undecorated classes as `@Directive`. **module-with-providers**: This migration adds an explicit generic type to `ModuleWithProviders`. As of v10, the generic type is required, so we need to re-run the migration again. **renderer-to-renderer2**: We don't need to re-run that migration again as the renderer has been already removed in v9. **missing-injectable**: This migration is exclusively concerned with undecorated providers referenced in an `NgModule`. We should re-run that migration again as we don't have proper backsliding prevention for this yet. We can consider adding an error in ngtsc for v10, or v11. In either way, we should re-run the migration. **dynamic-queries**: We ran this one in v9 to reduce code complexity in projects. Instead of explicitly passing `static: false`, not passing any object literal has the same semantics. We don't need to re-run the migration again since there is no good way to prevent backsliding and we cannot always run this migration for future versions (as some apps might actually intentionally use the explicit `static: false` option). PR Close #36921
2020-05-04 15:58:42 -04:00
const fromVersion = '9.0.0';
const toVersion = '10.0.0';
// Note that we need to specify "--allow-dirty" as the repository will become dirty
// if dependencies for the integration test are installed (i.e. modified lock files)
const updateCommandArgs = ['@angular/core', '--migrate-only', '--from', fromVersion,
'--to', toVersion, '--allow-dirty'];
// Print out the command that is used to run the migrations for easier debugging.
console.error(`Running "ng update ${updateCommandArgs.join(' ')}":`);
console.error(chalk.yellow(`------------------------------------------`));
const updateProcess = child_process.spawnSync(
'node', [cliBinPath, 'update', ...updateCommandArgs], {stdio: 'inherit', cwd: projectDir});
console.error(chalk.yellow(`------------------------------------------\n`));
if (updateProcess.status !== 0) {
console.error(chalk.red('✘ Running "ng update" failed. See output above.'));
process.exit(1);
}
let testsPassing = true;
// Check if each expectation file matches the actual file in the CLI project.
expectationFiles.forEach(relativeFilePath => {
const actualFilePath = relativeFilePath.replace(/_expected.ts$/, '.ts');
const expectedContent = fs.readFileSync(path.join(projectDir, relativeFilePath), 'utf8');
const actualContent = fs.readFileSync(path.join(projectDir, actualFilePath), 'utf8');
if (expectedContent === actualContent) {
console.log(chalk.green(`✓ File "${actualFilePath}" matches the expected output.`));
} else {
testsPassing = false;
console.error(chalk.red(`✘ File "${actualFilePath}" does not match the expected output.`));
console.log(chalk.yellow('--------------------------------------------'));
printColoredPatch(actualFilePath, actualContent, expectedContent);
console.log(chalk.yellow('--------------------------------------------\n'));
}
});
process.exit(testsPassing ? 0 : 1);
/** Compares the two strings and prints out a colored diff to stdout. */
function printColoredPatch(actualFilePath, actualContent, expectedContent) {
const patchLines =
diff.createPatch(
actualFilePath, expectedContent, actualContent, 'Expected content', 'Actual content')
.split(/\r?\n/);
// Walk through each line of the patch and print it. We omit the first two lines
// as these are the patch header and not relevant to the test.
for (let line of patchLines.slice(2)) {
if (line.startsWith('+')) {
console.log(chalk.green(line));
} else if (line.startsWith('-')) {
console.log(chalk.red(line));
} else {
console.log(chalk.grey(line));
}
}
}