Paul Gschwendtner 7fb3cc07de build: create integration test for ng-update migrations (#32349)
Creates anew integratin test for `ng-update` migrations. The
integration test uses an Angular CLI project that will be updated
using the latest package output symlinked from then `./dist/packages-dist`.

This allows us to ensure that migrations work in real CLI projects.
Another big benefit is that the Angular version is updated to the
latest. This is something we couldn't replicate in unit tests but
is extremely important. It's important because compilation could
break with newer Angular versions (note that migrations are always
executed after the new angular version has been installed).

PR Close #32349
2019-08-29 12:34:43 -07:00

81 lines
3.1 KiB
JavaScript

/**
* @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});
const fromVersion = '8.0.0';
const toVersion = '9.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));
}
}
}