Mike Brocchi 9f77c868d2 feat(@angular/cli): Update command runner.
This change removes the dependency of the ember-cli command structure.
2018-03-06 17:57:38 -05:00

151 lines
4.1 KiB
TypeScript

const SilentError = require('silent-error');
import { Command, CommandScope } from '../models/command';
import { overrideOptions } from '../utilities/override-options';
import { CliConfig } from '../models/config';
import { ServeTaskOptions, baseServeCommandOptions } from './serve';
import { checkPort } from '../utilities/check-port';
import { oneLine } from 'common-tags';
export interface E2eTaskOptions extends ServeTaskOptions {
config: string;
serve: boolean;
webdriverUpdate: boolean;
specs: string[];
suite: string;
elementExplorer: boolean;
}
export default class E2eCommand extends Command {
public readonly name = 'e2e';
public readonly description = 'Run e2e tests in existing project.';
public static aliases: string[] = ['e'];
public readonly scope = CommandScope.inProject;
public readonly arguments: string[] = [];
public options = overrideOptions([
...baseServeCommandOptions,
{
name: 'config',
type: String,
aliases: ['c'],
description: oneLine`
Use a specific config file.
Defaults to the protractor config file in angular-cli.json.
`
},
{
name: 'specs',
type: Array,
default: [],
aliases: ['sp'],
description: oneLine`
Override specs in the protractor config.
Can send in multiple specs by repeating flag (ng e2e --specs=spec1.ts --specs=spec2.ts).
`
},
{
name: 'suite',
type: String,
aliases: ['su'],
description: oneLine`
Override suite in the protractor config.
Can send in multiple suite by comma separated values (ng e2e --suite=suiteA,suiteB).
`
},
{
name: 'element-explorer',
type: Boolean,
default: false,
aliases: ['ee'],
description: 'Start Protractor\'s Element Explorer for debugging.'
},
{
name: 'webdriver-update',
type: Boolean,
default: true,
aliases: ['wu'],
description: 'Try to update webdriver.'
},
{
name: 'serve',
type: Boolean,
default: true,
aliases: ['s'],
description: oneLine`
Compile and Serve the app.
All non-reload related serve options are also available (e.g. --port=4400).
`
}
], [
{
name: 'port',
default: 0,
description: 'The port to use to serve the application.'
},
{
name: 'watch',
default: false,
description: 'Run build when files change.'
},
]);
validate(options: E2eTaskOptions) {
if (!options.config) {
const e2eConfig = CliConfig.fromProject().config.e2e;
if (!e2eConfig.protractor.config) {
throw new SilentError('No protractor config found in .angular-cli.json.');
}
}
return true;
}
run(options: E2eTaskOptions) {
const E2eTask = require('../tasks/e2e').E2eTask;
const e2eTask = new E2eTask({
ui: this.ui,
project: this.project
});
if (!options.config) {
const e2eConfig = CliConfig.fromProject().config.e2e;
options.config = e2eConfig.protractor.config;
}
if (options.serve) {
const ServeTask = require('../tasks/serve').default;
const serve = new ServeTask({
ui: this.ui,
project: this.project,
});
// Protractor will end the proccess, so we don't need to kill the dev server
// TODO: Convert this promise to use observables which will allow for retries.
return new Promise((resolve, reject) => {
let firstRebuild = true;
function rebuildCb(stats: any) {
// don't run re-run tests on subsequent rebuilds
const cleanBuild = !!!stats.compilation.errors.length;
if (firstRebuild && cleanBuild) {
firstRebuild = false;
return resolve(e2eTask.run(options));
} else {
return reject('Build did not succeed. Please fix errors before running e2e task');
}
}
checkPort(options.port, options.host)
.then((port: number) => options.port = port)
.then(() => serve.run(options, rebuildCb))
.catch(reject);
});
} else {
return e2eTask.run(options);
}
}
}