ci(docs-infra): test docs examples with Ivy (#28463)

PR Close #28463
This commit is contained in:
Brandon 2019-02-05 21:20:05 +00:00 committed by Miško Hevery
parent 570f735a2a
commit 99e3a04ea2
10 changed files with 1142 additions and 601 deletions

View File

@ -280,6 +280,27 @@ jobs:
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
- run: yarn --cwd aio example-e2e --setup --local --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} - run: yarn --cwd aio example-e2e --setup --local --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
test_docs_examples_ivy:
<<: *job_defaults
docker:
# Needed because the example e2e tests depend on Chrome.
- image: *browsers_docker_image
parallelism: 3
steps:
- checkout:
<<: *post_checkout
- *restore_cache
- attach_workspace:
at: dist
- *define_env_vars
- *download_yarn
# Install aio
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
# Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
# Since the parallelism is set to "3", there will be three parallel CircleCI containers
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
- run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
aio_preview: aio_preview:
<<: *job_defaults <<: *job_defaults
@ -593,6 +614,9 @@ workflows:
- test_docs_examples: - test_docs_examples:
requires: requires:
- build-npm-packages - build-npm-packages
- test_docs_examples_ivy:
requires:
- build-npm-packages
- aio_preview: - aio_preview:
# Only run on PR builds. (There can be no previews for non-PR builds.) # Only run on PR builds. (There can be no previews for non-PR builds.)
filters: filters:
@ -618,7 +642,8 @@ workflows:
- test_aio_local - test_aio_local
- test_aio_local_ivy - test_aio_local_ivy
- test_docs_examples - test_docs_examples
# Get the artifacts to publish from the build-npm-packages job - test_docs_examples_ivy
# Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout. # since the publishing script expects the legacy outputs layout.
- build-npm-packages - build-npm-packages
- build-ivy-npm-packages - build-ivy-npm-packages

View File

@ -57,7 +57,9 @@ dist/
# aot # aot
**/*.ngsummary.json **/*.ngsummary.json
upgrade-module/tsconfig-aot.json
!rollup-config.js !rollup-config.js
upgrade-module/rollup-config.js
aot-compiler/**/*.d.ts aot-compiler/**/*.d.ts
aot-compiler/**/*.factory.d.ts aot-compiler/**/*.factory.d.ts
upgrade-phonecat-2-hybrid/aot/**/* upgrade-phonecat-2-hybrid/aot/**/*
@ -84,5 +86,9 @@ upgrade-phonecat-2-hybrid/aot/**/*
*stackblitz.no-link.html *stackblitz.no-link.html
# ngUpgrade testing # ngUpgrade testing
upgrade-phonecat-1-typescript/tsconfig-aot.json
upgrade-phonecat-1-typescript/rollup-config.js
upgrade-phonecat-3-final/tsconfig-aot.json
upgrade-phonecat-3-final/rollup-config.js
!upgrade-phonecat-*/**/karma.conf.js !upgrade-phonecat-*/**/karma.conf.js
!upgrade-phonecat-*/**/karma-test-shim.js !upgrade-phonecat-*/**/karma-test-shim.js

View File

@ -57,6 +57,7 @@
"preserve-and-sync": "yarn docs", "preserve-and-sync": "yarn docs",
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"", "serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
"boilerplate:add": "node ./tools/examples/example-boilerplate add", "boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:add:ivy": "yarn boilerplate:add --ivy",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove", "boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
"boilerplate:test": "node tools/examples/test.js", "boilerplate:test": "node tools/examples/test.js",
"generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz", "generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz",
@ -167,4 +168,4 @@
"xregexp": "^4.0.0", "xregexp": "^4.0.0",
"yargs": "^7.0.2" "yargs": "^7.0.2"
} }
} }

View File

@ -78,23 +78,38 @@ BOILERPLATE_PATHS.universal = [
'package.json' 'package.json'
]; ];
BOILERPLATE_PATHS.ivy = {
systemjs: [
'rollup-config.js',
'tsconfig-aot.json'
],
cli: [
'src/tsconfig.app.json'
]
};
const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
class ExampleBoilerPlate { class ExampleBoilerPlate {
/** /**
* Add boilerplate files to all the examples * Add boilerplate files to all the examples
*/ */
add() { add(ivy = false) {
// Get all the examples folders, indicated by those that contain a `example-config.json` file // Get all the examples folders, indicated by those that contain a `example-config.json` file
const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules'); const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
throw new Error(`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
`Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`);
}
if (ivy) {
shelljs.exec(`yarn --cwd ${SHARED_PATH} ivy-ngcc`);
}
exampleFolders.forEach(exampleFolder => { exampleFolders.forEach(exampleFolder => {
const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME)); const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME));
if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
throw new Error(`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
`Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`);
}
// Link the node modules - requires admin access (on Windows) because it adds symlinks // Link the node modules - requires admin access (on Windows) because it adds symlinks
const destinationNodeModules = path.resolve(exampleFolder, 'node_modules'); const destinationNodeModules = path.resolve(exampleFolder, 'node_modules');
fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules); fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules);
@ -107,6 +122,12 @@ class ExampleBoilerPlate {
// Copy the boilerplate common files // Copy the boilerplate common files
BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath)); BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath));
// Copy Ivy specific files
if (ivy && BOILERPLATE_PATHS.ivy[boilerPlateType]) {
const ivyBoilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, 'ivy', boilerPlateType);
BOILERPLATE_PATHS.ivy[boilerPlateType].forEach(filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath));
}
}); });
} }
@ -114,13 +135,13 @@ class ExampleBoilerPlate {
* Remove all the boilerplate files from all the examples * Remove all the boilerplate files from all the examples
*/ */
remove() { remove() {
shelljs.exec('git clean -xdfq', {cwd: EXAMPLES_BASE_PATH}); shelljs.exec('git clean -xdfq', { cwd: EXAMPLES_BASE_PATH });
} }
main() { main() {
yargs yargs
.usage('$0 <cmd> [args]') .usage('$0 <cmd> [args]')
.command('add', 'add the boilerplate to each example', () => this.add()) .command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy))
.command('remove', 'remove the boilerplate from each example', () => this.remove()) .command('remove', 'remove the boilerplate from each example', () => this.remove())
.demandCommand(1, 'Please supply a command from the list above') .demandCommand(1, 'Please supply a command from the list above')
.argv; .argv;
@ -144,7 +165,7 @@ class ExampleBoilerPlate {
} }
loadJsonFile(filePath) { loadJsonFile(filePath) {
return fs.readJsonSync(filePath, {throws: false}) || {}; return fs.readJsonSync(filePath, { throws: false }) || {};
} }
normalizePath(filePath) { normalizePath(filePath) {

View File

@ -15,10 +15,36 @@ const PROTRACTOR_CONFIG_FILENAME = path.join(__dirname, './shared/protractor.con
const SJS_SPEC_FILENAME = 'e2e-spec.ts'; const SJS_SPEC_FILENAME = 'e2e-spec.ts';
const CLI_SPEC_FILENAME = 'e2e/src/app.e2e-spec.ts'; const CLI_SPEC_FILENAME = 'e2e/src/app.e2e-spec.ts';
const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
const IGNORED_EXAMPLES = [ // temporary ignores const IGNORED_EXAMPLES = [
// temporary ignores
]; ];
const fixmeIvyExamples = [
// fixmeIvy('unknown') movie list route is not rendering
'ajs-quick-reference',
// fixmeIvy('unknown') version value goes undefined when clicking Major button after clicking
// Minor button twice
'component-interaction',
// fixmeIvy('unknown') failed content projection and applied styles
'component-styles',
// fails due to incompatible AoT code with a tree-shakable provider and a non-type constructor
// argument
'dependency-injection',
// fixmeIvy('unknown') Error: Internal Error: The name heroForm is already defined in scope to be
// [object Object]
'forms',
// fixmeIvy('unknown') app fails at runtime due to missing external service (goog is undefined)
'i18n',
// fixmeIvy('unknown') ERROR in HostResourceResolver: could not resolve app/app.component.css
// in context of aio/content/examples/styleguide/src/01-01/app/heroes/hero.component.avoid.ts)
'styleguide'
];
if (argv.ivy) {
IGNORED_EXAMPLES.push(...fixmeIvyExamples);
}
/** /**
* Run Protractor End-to-End Tests for Doc Samples * Run Protractor End-to-End Tests for Doc Samples
* *
@ -43,30 +69,30 @@ function runE2e() {
// Run setup. // Run setup.
console.log('runE2e: setup boilerplate'); console.log('runE2e: setup boilerplate');
const installPackagesCommand = `example-use-${argv.local ? 'local' : 'npm'}`; const installPackagesCommand = `example-use-${argv.local ? 'local' : 'npm'}`;
const addBoilerplateCommand = 'boilerplate:add'; const addBoilerplateCommand = `boilerplate:add${argv.ivy ? ':ivy' : ''}`;
shelljs.exec(`yarn ${installPackagesCommand}`, { cwd: AIO_PATH }); shelljs.exec(`yarn ${installPackagesCommand}`, {cwd: AIO_PATH});
shelljs.exec(`yarn ${addBoilerplateCommand}`, { cwd: AIO_PATH }); shelljs.exec(`yarn ${addBoilerplateCommand}`, {cwd: AIO_PATH});
} }
const outputFile = path.join(AIO_PATH, './protractor-results.txt'); const outputFile = path.join(AIO_PATH, './protractor-results.txt');
return Promise.resolve() return Promise.resolve()
.then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard)) .then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard))
.then((status) => { .then((status) => {
reportStatus(status, outputFile); reportStatus(status, outputFile);
if (status.failed.length > 0) { if (status.failed.length > 0) {
return Promise.reject('Some test suites failed'); return Promise.reject('Some test suites failed');
} }
}).catch(function (e) { })
console.log(e); .catch(function(e) {
process.exitCode = 1; console.log(e);
}); process.exitCode = 1;
});
} }
// Finds all of the *e2e-spec.tests under the examples folder along with the corresponding apps // Finds all of the *e2e-spec.tests under the examples folder along with the corresponding apps
// that they should run under. Then run each app/spec collection sequentially. // that they should run under. Then run each app/spec collection sequentially.
function findAndRunE2eTests(filter, outputFile, shard) { function findAndRunE2eTests(filter, outputFile, shard) {
const shardParts = shard ? shard.split('/') : [0, 1]; const shardParts = shard ? shard.split('/') : [0, 1];
const shardModulo = parseInt(shardParts[0], 10); const shardModulo = parseInt(shardParts[0], 10);
const shardDivider = parseInt(shardParts[1], 10); const shardDivider = parseInt(shardParts[1], 10);
@ -78,45 +104,48 @@ function findAndRunE2eTests(filter, outputFile, shard) {
fs.writeFileSync(outputFile, header); fs.writeFileSync(outputFile, header);
// Run the tests sequentially. // Run the tests sequentially.
const status = { passed: [], failed: [] }; const status = {passed: [], failed: []};
return getE2eSpecs(EXAMPLES_PATH, filter) return getE2eSpecs(EXAMPLES_PATH, filter)
.then(e2eSpecPaths => { .then(e2eSpecPaths => {
console.log('All e2e specs:'); console.log('All e2e specs:');
logSpecs(e2eSpecPaths); logSpecs(e2eSpecPaths);
Object.keys(e2eSpecPaths).forEach(key => { Object.keys(e2eSpecPaths).forEach(key => {
const value = e2eSpecPaths[key]; const value = e2eSpecPaths[key];
e2eSpecPaths[key] = value.filter((p, index) => index % shardDivider === shardModulo); e2eSpecPaths[key] = value.filter((p, index) => index % shardDivider === shardModulo);
});
console.log(`E2e specs for shard ${shardParts.join('/')}:`);
logSpecs(e2eSpecPaths);
return e2eSpecPaths.systemjs.reduce((promise, specPath) => {
return promise.then(() => {
const examplePath = path.dirname(specPath);
return runE2eTestsSystemJS(examplePath, outputFile).then(ok => {
const arr = ok ? status.passed : status.failed;
arr.push(examplePath);
});
}); });
}, Promise.resolve())
.then(() => { console.log(`E2e specs for shard ${shardParts.join('/')}:`);
return e2eSpecPaths.cli.reduce((promise, specPath) => { logSpecs(e2eSpecPaths);
return promise.then(() => {
return runE2eTestsCLI(specPath, outputFile).then(ok => { return e2eSpecPaths.systemjs
const arr = ok ? status.passed : status.failed; .reduce(
arr.push(specPath); (promise, specPath) => {
return promise.then(() => {
const examplePath = path.dirname(specPath);
return runE2eTestsSystemJS(examplePath, outputFile).then(ok => {
const arr = ok ? status.passed : status.failed;
arr.push(examplePath);
});
});
},
Promise.resolve())
.then(() => {
return e2eSpecPaths.cli.reduce((promise, specPath) => {
return promise.then(() => {
return runE2eTestsCLI(specPath, outputFile).then(ok => {
const arr = ok ? status.passed : status.failed;
arr.push(specPath);
});
});
}, Promise.resolve());
}); });
}); })
}, Promise.resolve()); .then(() => {
const stopTime = new Date().getTime();
status.elapsedTime = (stopTime - startTime) / 1000;
return status;
}); });
})
.then(() => {
const stopTime = new Date().getTime();
status.elapsedTime = (stopTime - startTime) / 1000;
return status;
});
} }
// Start the example in appDir; then run protractor with the specified // Start the example in appDir; then run protractor with the specified
@ -126,8 +155,8 @@ function findAndRunE2eTests(filter, outputFile, shard) {
function runE2eTestsSystemJS(appDir, outputFile) { function runE2eTestsSystemJS(appDir, outputFile) {
const config = loadExampleConfig(appDir); const config = loadExampleConfig(appDir);
const appBuildSpawnInfo = spawnExt('yarn', [config.build], { cwd: appDir }); const appBuildSpawnInfo = spawnExt('yarn', [config.build], {cwd: appDir});
const appRunSpawnInfo = spawnExt('yarn', [config.run, '-s'], { cwd: appDir }, true); const appRunSpawnInfo = spawnExt('yarn', [config.run, '-s'], {cwd: appDir}, true);
let run = runProtractorSystemJS(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile); let run = runProtractorSystemJS(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile);
@ -140,40 +169,40 @@ function runE2eTestsSystemJS(appDir, outputFile) {
function runProtractorSystemJS(prepPromise, appDir, appRunSpawnInfo, outputFile) { function runProtractorSystemJS(prepPromise, appDir, appRunSpawnInfo, outputFile) {
const specFilename = path.resolve(`${appDir}/${SJS_SPEC_FILENAME}`); const specFilename = path.resolve(`${appDir}/${SJS_SPEC_FILENAME}`);
return prepPromise return prepPromise
.catch(function () { .catch(function() {
const emsg = `Application at ${appDir} failed to transpile.\n\n`; const emsg = `Application at ${appDir} failed to transpile.\n\n`;
console.log(emsg); console.log(emsg);
fs.appendFileSync(outputFile, emsg); fs.appendFileSync(outputFile, emsg);
return Promise.reject(emsg); return Promise.reject(emsg);
}) })
.then(function () { .then(function() {
let transpileError = false; let transpileError = false;
// Start protractor. // Start protractor.
console.log(`\n\n=========== Running aio example tests for: ${appDir}`); console.log(`\n\n=========== Running aio example tests for: ${appDir}`);
const spawnInfo = spawnExt('yarn', ['protractor', const spawnInfo = spawnExt(
PROTRACTOR_CONFIG_FILENAME, 'yarn',
`--specs=${specFilename}`, [
'--params.appDir=' + appDir, 'protractor', PROTRACTOR_CONFIG_FILENAME, `--specs=${specFilename}`,
'--params.outputFile=' + outputFile '--params.appDir=' + appDir, '--params.outputFile=' + outputFile
], { cwd: SHARED_PATH }); ],
{cwd: SHARED_PATH});
spawnInfo.proc.stderr.on('data', function (data) { spawnInfo.proc.stderr.on('data', function(data) {
transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString()); transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString());
}); });
return spawnInfo.promise.catch(function () { return spawnInfo.promise.catch(function() {
if (transpileError) { if (transpileError) {
const emsg = `${specFilename} failed to transpile.\n\n`; const emsg = `${specFilename} failed to transpile.\n\n`;
console.log(emsg); console.log(emsg);
fs.appendFileSync(outputFile, emsg); fs.appendFileSync(outputFile, emsg);
} }
return Promise.reject(); return Promise.reject();
}); });
}) })
.then( .then(
function () { return finish(appRunSpawnInfo.proc.pid, true); }, function() { return finish(appRunSpawnInfo.proc.pid, true); },
function () { return finish(appRunSpawnInfo.proc.pid, false); } function() { return finish(appRunSpawnInfo.proc.pid, false); });
);
} }
function finish(spawnProcId, ok) { function finish(spawnProcId, ok) {
@ -186,14 +215,14 @@ function finish(spawnProcId, ok) {
// Run e2e tests over the AOT build for projects that examples it. // Run e2e tests over the AOT build for projects that examples it.
function runProtractorAoT(appDir, outputFile) { function runProtractorAoT(appDir, outputFile) {
fs.appendFileSync(outputFile, '++ AoT version ++\n'); fs.appendFileSync(outputFile, '++ AoT version ++\n');
const aotBuildSpawnInfo = spawnExt('yarn', ['build:aot'], { cwd: appDir }); const aotBuildSpawnInfo = spawnExt('yarn', ['build:aot'], {cwd: appDir});
let promise = aotBuildSpawnInfo.promise; let promise = aotBuildSpawnInfo.promise;
const copyFileCmd = 'copy-dist-files.js'; const copyFileCmd = 'copy-dist-files.js';
if (fs.existsSync(appDir + '/' + copyFileCmd)) { if (fs.existsSync(appDir + '/' + copyFileCmd)) {
promise = promise.then(() => spawnExt('node', [copyFileCmd], { cwd: appDir }).promise); promise = promise.then(() => spawnExt('node', [copyFileCmd], {cwd: appDir}).promise);
} }
const aotRunSpawnInfo = spawnExt('yarn', ['serve:aot'], { cwd: appDir }, true); const aotRunSpawnInfo = spawnExt('yarn', ['serve:aot'], {cwd: appDir}, true);
return runProtractorSystemJS(promise, appDir, aotRunSpawnInfo, outputFile); return runProtractorSystemJS(promise, appDir, aotRunSpawnInfo, outputFile);
} }
@ -205,11 +234,12 @@ function runE2eTestsCLI(appDir, outputFile) {
console.log(`\n\n=========== Running aio example tests for: ${appDir}`); console.log(`\n\n=========== Running aio example tests for: ${appDir}`);
// `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed. // `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed.
const config = loadExampleConfig(appDir); const config = loadExampleConfig(appDir);
const commands = config.e2e || [{ cmd: 'yarn', args: ['e2e', '--prod', '--no-webdriver-update'] }]; const commands = config.e2e ||
[{cmd: 'yarn', args: ['e2e', (argv.ivy ? '--prod' : ''), '--no-webdriver-update']}];
const e2eSpawnPromise = commands.reduce((prevSpawnPromise, { cmd, args }) => { const e2eSpawnPromise = commands.reduce((prevSpawnPromise, {cmd, args}) => {
return prevSpawnPromise.then(() => { return prevSpawnPromise.then(() => {
const currSpawn = spawnExt(cmd, args, { cwd: appDir }); const currSpawn = spawnExt(cmd, args, {cwd: appDir});
return currSpawn.promise.then( return currSpawn.promise.then(
() => Promise.resolve(finish(currSpawn.proc.pid, true)), () => Promise.resolve(finish(currSpawn.proc.pid, true)),
() => Promise.reject(finish(currSpawn.proc.pid, false))); () => Promise.reject(finish(currSpawn.proc.pid, false)));
@ -217,25 +247,39 @@ function runE2eTestsCLI(appDir, outputFile) {
}, Promise.resolve()); }, Promise.resolve());
return e2eSpawnPromise.then( return e2eSpawnPromise.then(
() => { fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`); return true; }, () => {
() => { fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`); return false; }); fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`);
return true;
},
() => {
fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`);
return false;
});
} }
// Report final status. // Report final status.
function reportStatus(status, outputFile) { function reportStatus(status, outputFile) {
let log = ['']; let log = [''];
log.push('Suites ignored due to legacy guides:');
IGNORED_EXAMPLES.filter(example => !fixmeIvyExamples.find(ex => ex.startsWith(example)))
.forEach(function(val) { log.push(' ' + val); });
if (argv.ivy) {
log.push('');
log.push('Suites ignored due to breakage with Ivy:');
fixmeIvyExamples.forEach(function(val) { log.push(' ' + val); });
}
log.push('');
log.push('Suites passed:'); log.push('Suites passed:');
status.passed.forEach(function (val) { status.passed.forEach(function(val) { log.push(' ' + val); });
log.push(' ' + val);
});
if (status.failed.length == 0) { if (status.failed.length == 0) {
log.push('All tests passed'); log.push('All tests passed');
} else { } else {
log.push('Suites failed:'); log.push('Suites failed:');
status.failed.forEach(function (val) { status.failed.forEach(function(val) { log.push(' ' + val); });
log.push(' ' + val);
});
} }
log.push('\nElapsed time: ' + status.elapsedTime + ' seconds'); log.push('\nElapsed time: ' + status.elapsedTime + ' seconds');
log = log.join('\n'); log = log.join('\n');
@ -254,68 +298,59 @@ function spawnExt(command, args, options, ignoreClose = false) {
} catch (e) { } catch (e) {
console.log(e); console.log(e);
reject(e); reject(e);
return { proc: null, promise }; return {proc: null, promise};
} }
proc.stdout.on('data', function (data) { proc.stdout.on('data', function(data) { process.stdout.write(data.toString()); });
process.stdout.write(data.toString()); proc.stderr.on('data', function(data) { process.stdout.write(data.toString()); });
}); proc.on('close', function(returnCode) {
proc.stderr.on('data', function (data) {
process.stdout.write(data.toString());
});
proc.on('close', function (returnCode) {
console.log(`completed: ${descr} \n`); console.log(`completed: ${descr} \n`);
// Many tasks (e.g., tsc) complete but are actually errors; // Many tasks (e.g., tsc) complete but are actually errors;
// Confirm return code is zero. // Confirm return code is zero.
returnCode === 0 || ignoreClose ? resolve(0) : reject(returnCode); returnCode === 0 || ignoreClose ? resolve(0) : reject(returnCode);
}); });
proc.on('error', function (data) { proc.on('error', function(data) {
console.log(`completed with error: ${descr} \n`); console.log(`completed with error: ${descr} \n`);
console.log(data.toString()); console.log(data.toString());
reject(data); reject(data);
}); });
}); });
return { proc, promise }; return {proc, promise};
} }
function getE2eSpecs(basePath, filter) { function getE2eSpecs(basePath, filter) {
let specs = {}; let specs = {};
return getE2eSpecsFor(basePath, SJS_SPEC_FILENAME, filter).then(sjsPaths => { return getE2eSpecsFor(basePath, SJS_SPEC_FILENAME, filter)
specs.systemjs = sjsPaths; .then(sjsPaths => { specs.systemjs = sjsPaths; })
}).then(() => { .then(() => {
return getE2eSpecsFor(basePath, CLI_SPEC_FILENAME, filter).then(cliPaths => { return getE2eSpecsFor(basePath, CLI_SPEC_FILENAME, filter).then(cliPaths => {
return cliPaths.map(p => { return cliPaths.map(p => { return p.replace(`${CLI_SPEC_FILENAME}`, ''); });
return p.replace(`${CLI_SPEC_FILENAME}`, ''); });
}); })
}); .then(cliPaths => { specs.cli = cliPaths; })
}).then(cliPaths => { .then(() => specs);
specs.cli = cliPaths;
}).then(() => specs);
} }
// Find all e2e specs in a given example folder. // Find all e2e specs in a given example folder.
function getE2eSpecsFor(basePath, specFile, filter) { function getE2eSpecsFor(basePath, specFile, filter) {
// Only get spec file at the example root. // Only get spec file at the example root.
const e2eSpecGlob = `${filter ? `*${filter}*` : '*'}/${specFile}`; const e2eSpecGlob = `${filter ? ` * ${filter} * ` : '*'}/${specFile}`;
return globby(e2eSpecGlob, { cwd: basePath, nodir: true }) return globby(e2eSpecGlob, {cwd: basePath, nodir: true})
.then(paths => paths .then(
.filter(file => !IGNORED_EXAMPLES.some(ignored => file.startsWith(ignored))) paths => paths.filter(file => !IGNORED_EXAMPLES.some(ignored => file.startsWith(ignored)))
.map(file => path.join(basePath, file)) .map(file => path.join(basePath, file)));
);
} }
// Load configuration for an example. Used for SystemJS // Load configuration for an example. Used for SystemJS
function loadExampleConfig(exampleFolder) { function loadExampleConfig(exampleFolder) {
// Default config. // Default config.
let config = { let config = {build: 'build', run: 'serve:e2e'};
build: 'build',
run: 'serve:e2e'
};
try { try {
const exampleConfig = fs.readJsonSync(`${exampleFolder}/${EXAMPLE_CONFIG_FILENAME}`); const exampleConfig = fs.readJsonSync(`${exampleFolder}/${EXAMPLE_CONFIG_FILENAME}`);
Object.assign(config, exampleConfig); Object.assign(config, exampleConfig);
} catch (e) { } } catch (e) {
}
return config; return config;
} }

View File

@ -0,0 +1,15 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
],
"angularCompilerOptions": {
"enableIvy": "ngtsc",
"allowEmptyCodegenFiles": true
}
}

View File

@ -0,0 +1,21 @@
// #docregion
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
//paths are relative to the execution path
export default {
entry: 'app/main.js',
dest: 'aot/dist/build.js', // output a single application bundle
sourceMap: true,
sourceMapFile: 'aot/dist/build.js.map',
format: 'iife',
plugins: [
nodeResolve({ jsnext: true, module: true }),
commonjs({
include: ['node_modules/rxjs/**']
}),
uglify()
]
}

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"es2015",
"dom"
],
"removeComments": false,
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"app/app.module.ts",
"app/main.ts"
],
"angularCompilerOptions": {
"skipMetadataEmit": true,
"enableIvy": "ngtsc"
}
}

View File

@ -18,22 +18,22 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@angular/animations": "^7.0.0", "@angular/animations": "^7.1.0",
"@angular/common": "^7.0.0", "@angular/common": "^7.1.0",
"@angular/compiler": "^7.0.0", "@angular/compiler": "^7.1.0",
"@angular/core": "^7.0.0", "@angular/core": "^7.1.0",
"@angular/elements": "^7.0.0", "@angular/elements": "^7.1.0",
"@angular/forms": "^7.0.0", "@angular/forms": "^7.1.0",
"@angular/http": "^7.0.0", "@angular/http": "^7.1.0",
"@angular/platform-browser": "^7.0.0", "@angular/platform-browser": "^7.1.0",
"@angular/platform-browser-dynamic": "^7.0.0", "@angular/platform-browser-dynamic": "^7.1.0",
"@angular/router": "^7.0.0", "@angular/router": "^7.1.0",
"@angular/service-worker": "^7.0.0", "@angular/service-worker": "^7.1.0",
"@angular/upgrade": "^7.0.0", "@angular/upgrade": "^7.1.0",
"@nguniversal/common": "^7.0.0", "@nguniversal/common": "^7.1.0",
"@nguniversal/express-engine": "^7.0.0", "@nguniversal/express-engine": "^7.1.0",
"@nguniversal/module-map-ngfactory-loader": "^7.0.0", "@nguniversal/module-map-ngfactory-loader": "^7.1.0",
"angular-in-memory-web-api": "^0.6.0", "angular-in-memory-web-api": "github:brandonroberts/in-memory-web-api-bazel#50a34d8",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"express": "^4.14.1", "express": "^4.14.1",
"rxjs": "^6.3.0", "rxjs": "^6.3.0",
@ -42,11 +42,11 @@
"zone.js": "~0.8.26" "zone.js": "~0.8.26"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.10.0", "@angular-devkit/build-angular": "^0.11.0",
"@angular/cli": "^7.0.0", "@angular/cli": "^7.1.0",
"@angular/compiler-cli": "^7.0.0", "@angular/compiler-cli": "^7.1.0",
"@angular/language-service": "^7.0.0", "@angular/language-service": "^7.1.0",
"@angular/platform-server": "^7.0.0", "@angular/platform-server": "^7.1.0",
"@types/angular": "^1.6.47", "@types/angular": "^1.6.47",
"@types/angular-animate": "^1.5.10", "@types/angular-animate": "^1.5.10",
"@types/angular-mocks": "^1.6.0", "@types/angular-mocks": "^1.6.0",

File diff suppressed because it is too large Load Diff