From f9c43910021095e1bee1d1074e8788f4b0aee145 Mon Sep 17 00:00:00 2001 From: Sebastien Armand - sa250111 Date: Fri, 21 Feb 2014 16:52:54 +0800 Subject: [PATCH] feat(cli+config): allow defining multiple test suites in the config and running them separately from the command line. --- docs/getting-started.md | 33 +++++++++++++++++++++++++++++++++ lib/configParser.js | 26 ++++++++++++++++++++++++++ lib/runner.js | 23 ++++++++++++----------- package.json | 5 +++-- spec/suites/always_fail_spec.js | 5 +++++ spec/suites/ok_2_spec.js | 5 +++++ spec/suites/ok_spec.js | 5 +++++ spec/suitesConf.js | 31 +++++++++++++++++++++++++++++++ 8 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 spec/suites/always_fail_spec.js create mode 100644 spec/suites/ok_2_spec.js create mode 100644 spec/suites/ok_spec.js create mode 100644 spec/suitesConf.js diff --git a/docs/getting-started.md b/docs/getting-started.md index cf40be8d3..fec85f438 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -197,6 +197,39 @@ describe('angularjs homepage', function() { }); ``` +It is possible to separate your tests in various test suites. The configuration becomes: + +```javascript +// An example configuration file. +exports.config = { + // The address of a running selenium server. + seleniumAddress: 'http://localhost:4444/wd/hub', + + // Capabilities to be passed to the webdriver instance. + capabilities: { + 'browserName': 'chrome' + }, + + // Spec patterns are relative to the location of the spec file. They may + // include glob patterns. + suites: { + homepage: 'tests/e2e/modules/homepage/**/*Spec.js', + search: ['tests/e2e/modules/contact_search/**/*Spec.js', 'tests/e2e/modules/venue_search/**/*Spec.js'] + }, + + // Options to be passed to Jasmine-node. + jasmineNodeOpts: { + showColors: true, // Use colors in the command line report. + } +}; +``` + +You can then easily switch from the command line between running one or the other +suite of tests: + + protractor protractor.conf.js --suite hompage + +Will only run the homepage section of the tests. Further Reading --------------- diff --git a/lib/configParser.js b/lib/configParser.js index 45c470bb7..310cb5c7e 100644 --- a/lib/configParser.js +++ b/lib/configParser.js @@ -1,6 +1,7 @@ var path = require('path'), glob = require('glob'), util = require('util'), + _ = require('lodash'), protractor = require('./protractor.js'); // Coffee is required here to enable config files written in coffee-script. @@ -67,6 +68,14 @@ var merge_ = function(into, from) { return into; }; +/** + * Returns the item if it's an array or puts the item in an array + * if it was not one already. + */ +var makeArray = function(item) { + return _.isArray(item) ? item : [item]; +}; + /** * Resolve a list of file patterns into a list of individual file paths. * @@ -98,6 +107,23 @@ ConfigParser.resolveFilePatterns = return resolvedFiles; }; +/** + * Returns only the specs that should run currently based on `config.suite` + * + * @return {Array} An array of globs locating the spec files + */ +ConfigParser.getSpecs = function(config) { + if (config.suite) { + return config.suites[config.suite]; + } + + var specs = config.specs || []; + _.forEach(config.suites, function(suite) { + specs = _.union(specs, makeArray(suite)); + }); + + return specs; +} /** * Add the options in the parameter config to this runner instance. diff --git a/lib/runner.js b/lib/runner.js index ad76cd3fc..46286e530 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -46,14 +46,14 @@ var Runner = function(config) { /** * Execute the Runner's test cases through Jasmine. * - * @private + * @private * @param {Array} specs Array of Directory Path Strings * @param done A callback for when tests are finished. */ Runner.prototype.runJasmine_ = function(specs, done) { var minijn = require('minijasminenode'), self = this; - + require('../jasminewd'); webdriver.promise.controlFlow().execute(function() { self.runTestPreparers_(); @@ -76,7 +76,7 @@ Runner.prototype.runJasmine_ = function(specs, done) { /** * Execute the Runner's test cases through Mocha. * - * @private + * @private * @param {Array} specs Array of Directory Path Strings * @param done A callback for when tests are finished. */ @@ -127,7 +127,7 @@ Runner.prototype.runMocha_ = function(specs, done) { /** * Execute the Runner's test cases through Cucumber. * - * @private + * @private * @param {Array} specs Array of Directory Path Strings * @param done A callback for when tests are finished. */ @@ -190,7 +190,7 @@ Runner.prototype.runCucumber_ = function(specs, done) { /** * Internal helper for abstraction of polymorphic filenameOrFn properties. - * @private + * @private * @param {Array} source The Array that we'll be iterating through * as we evaluate whether to require or execute each item. */ @@ -214,7 +214,7 @@ Runner.prototype.runFilenamesOrFns_ = function(source) { /** * Registrar for testPreparers - executed right before tests run. - * @public + * @public * @param {string/Fn} filenameOrFn */ Runner.prototype.registerTestPreparer = function(filenameOrFn) { @@ -224,7 +224,7 @@ Runner.prototype.registerTestPreparer = function(filenameOrFn) { /** * Executor of testPreparers - * @private + * @private */ Runner.prototype.runTestPreparers_ = function() { this.runFilenamesOrFns_(this.preparers_); @@ -240,7 +240,7 @@ Runner.prototype.runTestPreparers_ = function() { * 2) if seleniumAddress is given, use that * 3) if a sauceAccount is given, use that. * 4) if a seleniumServerJar is specified, use that - * 5) try to find the seleniumServerJar in protractor/selenium + * 5) try to find the seleniumServerJar in protractor/selenium */ Runner.prototype.loadDriverProvider_ = function() { var runnerPath; @@ -284,7 +284,7 @@ Runner.prototype.getConfig = function() { /** * Sets up convenience globals for test specs - * @private + * @private */ Runner.prototype.setupGlobals_ = function(driver) { var browser = protractor.wrapDriver( @@ -320,8 +320,9 @@ Runner.prototype.run = function() { // Determine included and excluded specs based on file pattern. excludes = ConfigParser.resolveFilePatterns( this.config_.exclude, true, this.config_.configDir); + specs = ConfigParser.resolveFilePatterns( - this.config_.specs, false, this.config_.configDir).filter(function(path) { + ConfigParser.getSpecs(this.config_), false, this.config_.configDir).filter(function(path) { return excludes.indexOf(path) < 0; }); @@ -365,7 +366,7 @@ Runner.prototype.run = function() { throw new Error('config.framework (' + self.config_.framework + ') is not a valid framework.'); } - + return deferred.promise; // 3) Teardown diff --git a/package.json b/package.json index 37263f92d..d61c27716 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "glob": ">=3.1.14", "adm-zip": ">=0.4.2", "optimist": "~0.6.0", - "q": "1.0.0" + "q": "1.0.0", + "lodash": "~2.4.1" }, "devDependencies": { "expect.js": "~0.2.0", @@ -43,7 +44,7 @@ }, "main": "lib/protractor.js", "scripts": { - "test": "node lib/cli.js spec/basicConf.js; node lib/cli.js spec/multiConf.js; node lib/cli.js spec/altRootConf.js; node lib/cli.js spec/onPrepareConf.js; node lib/cli.js spec/mochaConf.js; node lib/cli.js spec/cucumberConf.js; node lib/cli.js spec/withLoginConf.js; node_modules/.bin/minijasminenode jasminewd/spec/adapterSpec.js spec/unit/*.js docs/spec/*.js" + "test": "node lib/cli.js spec/basicConf.js; node lib/cli.js spec/multiConf.js; node lib/cli.js spec/altRootConf.js; node lib/cli.js spec/onPrepareConf.js; node lib/cli.js spec/mochaConf.js; node lib/cli.js spec/cucumberConf.js; node lib/cli.js spec/withLoginConf.js; node_modules/.bin/minijasminenode jasminewd/spec/adapterSpec.js spec/unit/*.js docs/spec/*.js; node lib/cli.js spec/suitesConf.js --suite okmany; node lib/cli.js spec/suitesConf.js --suite okspec" }, "license": "MIT", "version": "0.20.1", diff --git a/spec/suites/always_fail_spec.js b/spec/suites/always_fail_spec.js new file mode 100644 index 000000000..b63326bc6 --- /dev/null +++ b/spec/suites/always_fail_spec.js @@ -0,0 +1,5 @@ +describe('This test suite', function(){ + it('should never be ran through the --suite option', function(){ + expect(true).toBe(false); + }); +}); \ No newline at end of file diff --git a/spec/suites/ok_2_spec.js b/spec/suites/ok_2_spec.js new file mode 100644 index 000000000..9492b9a1f --- /dev/null +++ b/spec/suites/ok_2_spec.js @@ -0,0 +1,5 @@ +describe('This test suite', function(){ + it('should be ran through the --suite option', function(){ + expect(true).toBe(true); + }); +}); \ No newline at end of file diff --git a/spec/suites/ok_spec.js b/spec/suites/ok_spec.js new file mode 100644 index 000000000..9492b9a1f --- /dev/null +++ b/spec/suites/ok_spec.js @@ -0,0 +1,5 @@ +describe('This test suite', function(){ + it('should be ran through the --suite option', function(){ + expect(true).toBe(true); + }); +}); \ No newline at end of file diff --git a/spec/suitesConf.js b/spec/suitesConf.js new file mode 100644 index 000000000..220b1efbd --- /dev/null +++ b/spec/suitesConf.js @@ -0,0 +1,31 @@ +// The main suite of Protractor tests. +exports.config = { + seleniumAddress: 'http://localhost:4444/wd/hub', + + // Spec patterns are relative to this directory. + suites: { + okspec: 'suites/ok_spec.js', + okmany: ['suites/ok_spec.js', 'suites/ok_2_spec.js'], + failingtest: 'suites/always_fail_spec.js' + } + + // Exclude patterns are relative to this directory. + exclude: [ + 'basic/exclude*.js' + ], + + chromeOnly: false, + + capabilities: { + 'browserName': 'chrome' + }, + + baseUrl: 'http://localhost:8000', + + params: { + login: { + user: 'Jane', + password: '1234' + } + } +};