diff --git a/package.json b/package.json index ff3afddc2e42..36448cd4cabb 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "@types/node": "^6.0.36", "@types/request": "0.0.30", "@types/rimraf": "0.0.25-alpha", + "@types/sinon": "^1.16.33", "@types/semver": "^5.3.30", "@types/source-map": "^0.5.0", "@types/webpack": "^1.12.22-alpha", @@ -161,7 +162,7 @@ "request": "^2.74.0", "resolve-bin": "^0.4.0", "rewire": "^2.5.1", - "sinon": "^1.17.3", + "sinon": "^1.17.6", "tree-kill": "^1.0.0", "ts-node": "^1.3.0" } diff --git a/packages/angular-cli/commands/e2e.ts b/packages/angular-cli/commands/e2e.ts index 5099354429eb..046dfa87ce49 100644 --- a/packages/angular-cli/commands/e2e.ts +++ b/packages/angular-cli/commands/e2e.ts @@ -1,12 +1,21 @@ const Command = require('../ember-cli/lib/models/command'); -import {E2eTask} from '../tasks/e2e'; -import {CliConfig} from '../models/config'; +import { E2eTask } from '../tasks/e2e'; +import { CliConfig } from '../models/config'; + +export interface E2eOptions { + suite?: string; +} const E2eCommand = Command.extend({ name: 'e2e', description: 'Run e2e tests in existing project', works: 'insideProject', - run: function () { + + availableOptions: [ + { name: 'suite', type: String, default: null }, + ], + + run: function (commandOptions: E2eOptions) { this.project.ngConfig = this.project.ngConfig || CliConfig.fromProject(); const e2eTask = new E2eTask({ @@ -14,7 +23,7 @@ const E2eCommand = Command.extend({ project: this.project }); - return e2eTask.run(); + return e2eTask.run(commandOptions); } }); diff --git a/packages/angular-cli/tasks/e2e.ts b/packages/angular-cli/tasks/e2e.ts index 4de5cbac8fc7..1e85721b17f8 100644 --- a/packages/angular-cli/tasks/e2e.ts +++ b/packages/angular-cli/tasks/e2e.ts @@ -1,15 +1,21 @@ const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; -import {exec} from 'child_process'; - +import { exec } from 'child_process'; +import { E2eOptions } from '../commands/e2e'; export const E2eTask = Task.extend({ - run: function () { + run: function (options: E2eOptions) { + const commandArgs: string[] = []; const ui = this.ui; let exitCode = 0; + if (options.suite) { + commandArgs.push(`--suite="${options.suite}"`); + } + return new Promise((resolve) => { - exec(`npm run e2e -- ${this.project.ngConfig.config.e2e.protractor.config}`, + const protractorConfig = this.project.ngConfig.config.e2e.protractor.config; + exec(`npm run e2e -- ${protractorConfig} ${commandArgs.join(' ')}`, (err: NodeJS.ErrnoException, stdout: string, stderr: string) => { ui.writeLine(stdout); if (err) { diff --git a/tests/helpers/mock-project.js b/tests/helpers/mock-project.js new file mode 100644 index 000000000000..de1b1daca590 --- /dev/null +++ b/tests/helpers/mock-project.js @@ -0,0 +1,59 @@ +'use strict'; + +var Project = require('angular-cli/ember-cli/lib/models/project'); +var MockUI = require('./mock-ui'); + +function MockProject() { + var root = process.cwd(); + var pkg = {}; + var ui = new MockUI(); + Project.apply(this, [root, pkg, ui]); +} + +MockProject.prototype.require = function(file) { + if (file === './server') { + return function() { + return { + listen: function() { + arguments[arguments.length - 1](); + } + }; + }; + } +}; + +MockProject.prototype.config = function() { + return this._config || { + baseURL: '/', + locationType: 'auto' + }; +}; + +MockProject.prototype.has = function(key) { + return (/server/.test(key)); +}; + +MockProject.prototype.name = function() { + return 'mock-project'; +}; + +MockProject.prototype.initializeAddons = Project.prototype.initializeAddons; +MockProject.prototype.hasDependencies = function() { + return true; +}; +MockProject.prototype.discoverAddons = Project.prototype.discoverAddons; +MockProject.prototype.addIfAddon = Project.prototype.addIfAddon; +MockProject.prototype.supportedInternalAddonPaths = Project.prototype.supportedInternalAddonPaths; +MockProject.prototype.setupBowerDirectory = Project.prototype.setupBowerDirectory; +MockProject.prototype.setupNodeModulesPath = Project.prototype.setupNodeModulesPath; +MockProject.prototype.isEmberCLIProject = Project.prototype.isEmberCLIProject; +MockProject.prototype.isEmberCLIAddon = Project.prototype.isEmberCLIAddon; +MockProject.prototype.findAddonByName = Project.prototype.findAddonByName; +MockProject.prototype.dependencies = function() { + return []; +}; +MockProject.prototype.isEmberCLIAddon = function() { + return false; +}; + +module.exports = MockProject; diff --git a/tests/runner.js b/tests/runner.js index ab9a4e1f4955..06a11838fb03 100644 --- a/tests/runner.js +++ b/tests/runner.js @@ -7,7 +7,7 @@ var Mocha = require('mocha'); var glob = require('glob'); var path = require('path'); -var root = 'tests/{acceptance,models}'; +var root = 'tests/{acceptance,unit}'; var specFiles = glob.sync(root + '/**/*.spec.*'); var mocha = new Mocha({ timeout: 5000, reporter: 'spec' }); diff --git a/tests/unit/commands/e2e.spec.ts b/tests/unit/commands/e2e.spec.ts new file mode 100644 index 000000000000..cb755aae8083 --- /dev/null +++ b/tests/unit/commands/e2e.spec.ts @@ -0,0 +1,50 @@ +import E2eCommand from 'angular-cli/commands/e2e'; +import { CliConfig } from 'angular-cli/models/config/config'; +import { stub, SinonStub } from 'sinon'; +import { expect } from 'chai'; +import * as proc from 'child_process'; + +const MockUI = require('../../helpers/mock-ui'); +const MockProject = require('../../helpers/mock-project'); + +function createProject() { + const project = new MockProject(); + project.isEmberCLIProject = () => true; + project.ngConfig = CliConfig.fromJson({ + e2e: { + protractor: { + config: 'some-config' + } + } + }); + + return project; +} + +describe('e2e command', () => { + let command: any; + let exec: SinonStub; + + beforeEach(() => { + command = new E2eCommand({ + settings: {}, + project: createProject(), + ui: new MockUI(), + }); + }); + + beforeEach(() => { + exec = stub(proc, 'exec').callsArg(1); + }); + + afterEach(() => { + exec.restore(); + }); + + it('passes through the suite option', () => { + return command.validateAndRun(['--suite', 'suiteA,suite B']).then(() => { + expect(exec.calledOnce).to.be.true; + expect(exec.firstCall.args[0]).to.have.string(' --suite="suiteA,suite B"'); + }); + }); +}); diff --git a/tests/models/config.spec.ts b/tests/unit/models/config.spec.ts similarity index 100% rename from tests/models/config.spec.ts rename to tests/unit/models/config.spec.ts diff --git a/tests/models/spec-schema.d.ts b/tests/unit/models/spec-schema.d.ts similarity index 100% rename from tests/models/spec-schema.d.ts rename to tests/unit/models/spec-schema.d.ts diff --git a/tests/models/spec-schema.json b/tests/unit/models/spec-schema.json similarity index 100% rename from tests/models/spec-schema.json rename to tests/unit/models/spec-schema.json