Socket
Socket
Sign inDemoInstall

protractor

Package Overview
Dependencies
Maintainers
1
Versions
103
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

protractor - npm Package Compare versions

Comparing version 0.18.1 to 0.19.0

lib/configParser.js

2

bin/elementexplorer.js

@@ -136,3 +136,3 @@ #!/usr/bin/env node

global.element = browser.element;
global.by = protractor.By;
global.by = global.By = protractor.By;
global.list = list;

@@ -139,0 +139,0 @@

@@ -0,1 +1,73 @@

# 0.19.1
_Note: Major version 0 releases are for initial development, and backwards incompatible changes may be introduced at any time._
## Features
- ([77393d0](https://github.com/angular/protractor/commit/77393d08343ef16ddc2b8042e187c9d68fe7bf2f)), ([6848180](https://github.com/angular/protractor/commit/68481801d506941ebf00fab71f87be510c7a87ba)), ([cca82ca](https://github.com/angular/protractor/commit/cca82caab6ae444b368eebe040a69967d774737e))
feat(runner/launcher): major runner updates to allow multiple capabilities
Adding simultaneous runner capability (grid-style), refactoring launch/runner init system, and
abstracting out configParser module.
- ([642de06](https://github.com/angular/protractor/commit/642de06e8bbabf82c7b8e0a64a280df5c4daf01c))
feat(protractor): add removeMockModule method
- ([88c339f](https://github.com/angular/protractor/commit/88c339fc1d392717a0a5b8265806934b40158c5f))
feat(runner): add adapter for cucumber.js
Conflicts:
lib/runner.js
## Bug Fixes
- ([8924bbc](https://github.com/angular/protractor/commit/8924bbca9e8f04073a29534bf16b0867a1ede7a0))
fix(cli): convert capabilities arguments to dot-notation for WebDriver compatibility
- ([a96d32f](https://github.com/angular/protractor/commit/a96d32f44a92ba9447fc843bc0aca7b91b777635))
fix(webdriver-manager): upcase in IE download url
The url for the Win32 version of the IEDriverServer is apparently case sensitive: _win32_ vs
_Win32_
## Breaking Changes
- ([05eb42b](https://github.com/angular/protractor/commit/05eb42bb482c7cb36b48af1a86210afc442aa112))
refactor(locators): moves scope in locators to last argument
scope defaults to document, and is an optional argument so now be moved to the end. Came up from
debugging and trying to use window.clientSideScripts.findInputs('username'); which failed.
Refactored to match original intent.
BREAKING CHANGE: anything relying on clientsidescripts should no longer pass
element scope as first argument.
Before:
window.clientSideScripts.findInputs(document, 'username');
After:
window.clientSideScripts.findInputs(document, 'username');
Also, any custom locators using addLocator will now break since the
arguments order has chnaged. To migrate the code follow the example below:
Before:
var findMenuItem = function() {
var domScope = arguments[0];
var myArg = arguments[1];
// balh blah blah
};
by.addLocator('menuItem', findMenuItem);
After:
var findMenuItem = function() {
var myArg = arguments[0];
var domScope = arguments[1];
// balh blah blah
};
by.addLocator('menuItem', findMenuItem);
Closes #497
# 0.18.1

@@ -2,0 +74,0 @@ _Note: Major version 0 releases are for initial development, and backwards incompatible changes may be introduced at any time._

@@ -40,2 +40,17 @@ Setting up your Browser

Testing against multiple browsers
---------------------------------
If you would like to test against multiple browsers at once, use the multiCapabilities configuration option.
```javascript
multiCapabilities: [{
'browserName': 'firefox'
}, {
'browserName': 'chrome'
}]
```
Protractor will run tests in parallel against each set of capabilities. Please note that if multiCapabilities is defined, the runner will ignore the `capabilities` configuration.
PhantomJS

@@ -50,4 +65,14 @@ -------------------------------------

// should be able to omit this property if phantomjs installed globally
'phantomjs.binary.path':'./node_modules/phantomjs/bin/phantomjs'
/*
* Can be used to specify the phantomjs binary path.
* This can generally be ommitted if you installed phantomjs globally.
*/
'phantomjs.binary.path':'./node_modules/phantomjs/bin/phantomjs',
/*
* Command line arugments to pass to phantomjs.
* Can be ommitted if no arguments need to be passed.
* Acceptable cli arugments: https://github.com/ariya/phantomjs/wiki/API-Reference#wiki-command-line-options
*/
'phantomjs.cli.args':['--logfile=PATH', '--loglevel=DEBUG']
}

@@ -54,0 +79,0 @@ ```

@@ -64,4 +64,4 @@ Debugging Protractor Tests

We use `browser.debugger();` instead of node's `debugger;` statement so that
the test pauses after the get command has beenexecuted*. Using `debugger;`
pauses the test after the get command isscheduled* but has not yet
the test pauses after the get command has been executed. Using `debugger;`
pauses the test after the get command is scheduled but has not yet
been sent to the browser.

@@ -80,2 +80,5 @@

// Should return the input element with model 'username'.
// You can also limit the scope of the locator
> window.clientSideScripts.findInputs('username', document.getElementById('#myEl'));
```

@@ -110,3 +113,3 @@

./bin/elementexplorer.js <urL>
node ./bin/elementexplorer.js <urL>

@@ -150,3 +153,3 @@ This will load up the URL on webdriver and put the terminal into a REPL loop.

stream.write(buf = new Buffer(data, 'base64'));
stream.write(new Buffer(data, 'base64'));
stream.end();

@@ -153,0 +156,0 @@ }

/**
* The command line interface for interacting with the Protractor runner.
* It takes care of parsing the config file and command line options.
* It takes care of parsing command line options.
*

@@ -27,3 +27,3 @@ * Values from command line options override values from the config.

var path = require('path');
var runner = require('./runner.js');
var child = require('child_process');
var argv = require('optimist').

@@ -71,5 +71,29 @@ usage('Usage: protractor [options] [configFile]\n' +

// WebDriver capabilities properties require dot notation, but optimist parses
// that into an object. Re-flatten it.
var flattenObject = function(obj) {
var prefix = arguments[1] || '';
var out = arguments[2] || {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
typeof obj[prop] === 'object' ?
flattenObject(obj[prop], prefix + prop + '.', out) :
out[prefix + prop] = obj[prop];
}
}
return out;
};
// Any file names should be resolved relative to the current working directory.
var processFilePatterns = function(list) {
if (argv.capabilities) {
argv.capabilities = flattenObject(argv.capabilities);
}
/**
* Helper to resolve comma separated lists of file pattern strings relative to
* the cwd.
*
* @private
* @param {Array} list
*/
var processFilePatterns_ = function(list) {
var patterns = list.split(',');

@@ -80,26 +104,12 @@ patterns.forEach(function(spec, index, arr) {

return patterns;
}
};
if (argv.specs) {
argv.specs = processFilePatterns(argv.specs);
argv.specs = processFilePatterns_(argv.specs);
}
if (argv.exclude) {
argv.exclude = processFilePatterns(argv.exclude);
if (argv.excludes) {
argv.excludes = processFilePatterns_(argv.excludes);
}
['seleniumServerJar', 'chromeDriver', 'onPrepare'].forEach(function(name) {
if (argv[name]) {
argv[name] = path.resolve(process.cwd(), argv[name]);
}
});
var configFilename = argv._[0];
if (configFilename) {
var configPath = path.resolve(process.cwd(), configFilename);
var config = require(configPath).config;
config.configDir = path.dirname(configPath);
runner.addConfig(config);
}
runner.addConfig(argv);
runner.runOnce();
// Run the launcher
require('./launcher').init(argv);

@@ -33,4 +33,4 @@ /**

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The binding, e.g. {{cat.name}}.
* arguments[0] {string} The binding, e.g. {{cat.name}}.
* arguments[1] {Element} The scope of the search.
*

@@ -40,4 +40,4 @@ * @return {Array.<Element>} The elements containing the binding.

clientSideScripts.findBindings = function() {
var using = arguments[0] || document;
var binding = arguments[1];
var binding = arguments[0];
var using = arguments[1] || document;
var bindings = using.getElementsByClassName('ng-binding');

@@ -62,5 +62,5 @@ var matches = [];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[2] {number} The row index.
* arguments[0] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[1] {number} The row index.
* arguments[2] {Element} The scope of the search.
*

@@ -71,5 +71,5 @@ * @return {Array.<Element>} The row of the repeater, or an array of elements

clientSideScripts.findRepeaterRows = function() {
var using = arguments[0] || document;
var repeater = arguments[1];
var index = arguments[2];
var repeater = arguments[0];
var index = arguments[1];
var using = arguments[2] || document;

@@ -116,4 +116,4 @@ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[0] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[1] {Element} The scope of the search.
*

@@ -123,4 +123,4 @@ * @return {Array.<Element>} All rows of the repeater.

clientSideScripts.findAllRepeaterRows = function() {
var using = arguments[0] || document;
var repeater = arguments[1];
var repeater = arguments[0];
var using = arguments[1] || document;

@@ -161,6 +161,6 @@ var rows = [];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[2] {number} The row index.
* arguments[3] {string} The column binding, e.g. '{{cat.name}}'.
* arguments[0] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[1] {number} The row index.
* arguments[2] {string} The column binding, e.g. '{{cat.name}}'.
* arguments[3] {Element} The scope of the search.
*

@@ -171,6 +171,6 @@ * @return {Array.<Element>} The element in an array.

var matches = [];
var using = arguments[0] || document;
var repeater = arguments[1];
var index = arguments[2];
var binding = arguments[3];
var repeater = arguments[0];
var index = arguments[1];
var binding = arguments[2];
var using = arguments[3] || document;

@@ -250,5 +250,5 @@ var rows = [];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[2] {string} The column binding, e.g. '{{cat.name}}'.
* arguments[0] {string} The text of the repeater, e.g. 'cat in cats'.
* arguments[1] {string} The column binding, e.g. '{{cat.name}}'.
* arguments[2] {Element} The scope of the search.
*

@@ -259,5 +259,5 @@ * @return {Array.<Element>} The elements in the column.

var matches = [];
var using = arguments[0] || document;
var repeater = arguments[1];
var binding = arguments[2];
var repeater = arguments[0];
var binding = arguments[1];
var using = arguments[2] || document;

@@ -336,4 +336,4 @@ var rows = [];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The model name.
* arguments[0] {string} The model name.
* arguments[1] {Element} The scope of the search.
*

@@ -343,4 +343,4 @@ * @return {Array.<Element>} The matching input elements.

clientSideScripts.findInputs = function() {
var using = arguments[0] || document;
var model = arguments[1];
var model = arguments[0];
var using = arguments[1] || document;
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

@@ -359,4 +359,4 @@ for (var p = 0; p < prefixes.length; ++p) {

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The model name.
* arguments[0] {string} The model name.
* arguments[1] {Element} The scope of the search.
*

@@ -366,4 +366,4 @@ * @return {Array.<Element>} The matching elements.

clientSideScripts.findByModel = function() {
var using = arguments[0] || document;
var model = arguments[1];
var model = arguments[0];
var using = arguments[1] || document;
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

@@ -382,4 +382,4 @@ for (var p = 0; p < prefixes.length; ++p) {

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The exact text to match.
* arguments[0] {string} The exact text to match.
* arguments[1] {Element} The scope of the search.
*

@@ -389,4 +389,4 @@ * @return {Array.<Element>} The matching elements.

clientSideScripts.findByButtonText = function() {
var using = arguments[0] || document;
var searchText = arguments[1];
var searchText = arguments[0];
var using = arguments[1] || document;
var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');

@@ -413,4 +413,4 @@ var matches = [];

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The exact text to match.
* arguments[0] {string} The exact text to match.
* arguments[1] {Element} The scope of the search.
*

@@ -420,4 +420,4 @@ * @return {Array.<Element>} The matching elements.

clientSideScripts.findByPartialButtonText = function() {
var using = arguments[0] || document;
var searchText = arguments[1];
var searchText = arguments[0];
var using = arguments[1] || document;
var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');

@@ -442,7 +442,7 @@ var matches = [];

/**
/**
* Find multiple select elements by model name.
*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The model name.
* arguments[0] {string} The model name.
* arguments[1] {Element} The scope of the search.
*

@@ -452,4 +452,4 @@ * @return {Array.<Element>} The matching select elements.

clientSideScripts.findSelects = function() {
var using = arguments[0] || document;
var model = arguments[1];
var model = arguments[0];
var using = arguments[1] || document;
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

@@ -468,4 +468,4 @@ for (var p = 0; p < prefixes.length; ++p) {

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {string} The model name.
* arguments[0] {string} The model name.
* arguments[1] {Element} The scope of the search.
*

@@ -475,4 +475,4 @@ * @return {Array.<Element>} The matching select elements.

clientSideScripts.findSelectedOptions = function() {
var using = arguments[0] || document;
var model = arguments[1];
var model = arguments[0];
var using = arguments[1] || document;
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

@@ -491,4 +491,4 @@ for (var p = 0; p < prefixes.length; ++p) {

*
* arguments[0] {Element} The scope of the search.
* arguments[1] {String} The model name.
* arguments[0] {String} The model name.
* arguments[1] {Element} The scope of the search.
*

@@ -498,4 +498,4 @@ * @return {Array.<Element>} An array of matching textarea elements.

clientSideScripts.findTextareas = function() {
var using = arguments[0] || document;
var model = arguments[1];
var model = arguments[0];
var using = arguments[1] || document;

@@ -502,0 +502,0 @@ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];

@@ -29,5 +29,4 @@ var util = require('util');

* the browser. This script will be passed an array of arguments
* that begins with the element scoping the search, and then
* contains any args passed into the locator. It should return
* an array of elements.
* that contains any args passed into the locator followed by the
* element scoping the search. It should return an array of elements.
*/

@@ -39,6 +38,6 @@ ProtractorBy.prototype.addLocator = function(name, script) {

return driver.findElements(
webdriver.By.js(script), using, varArgs);
webdriver.By.js(script), varArgs, using);
},
message: 'by.' + name + '("' + varArgs + '")'
}
};
};

@@ -57,3 +56,3 @@ };

webdriver.By.js(clientSideScripts.findBindings),
using, bindingDescriptor);
bindingDescriptor, using);
},

@@ -74,3 +73,3 @@ message: 'by.binding("' + bindingDescriptor + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findSelects), using, model);
webdriver.By.js(clientSideScripts.findSelects), model, using);
},

@@ -90,3 +89,3 @@ message: 'by.select("' + model + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findSelectedOptions), using, model);
webdriver.By.js(clientSideScripts.findSelectedOptions), model, using);
},

@@ -107,3 +106,3 @@ message: 'by.selectedOption("' + model + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findInputs), using, model);
webdriver.By.js(clientSideScripts.findInputs), model, using);
},

@@ -123,3 +122,3 @@ message: 'by.input("' + model + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findByModel), using, model);
webdriver.By.js(clientSideScripts.findByModel), model, using);
},

@@ -139,3 +138,3 @@ message: 'by.model("' + model + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findByButtonText), using, searchText);
webdriver.By.js(clientSideScripts.findByButtonText), searchText, using);
},

@@ -155,3 +154,3 @@ message: 'by.buttonText("' + searchText + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findByPartialButtonText), using, searchText);
webdriver.By.js(clientSideScripts.findByPartialButtonText), searchText, using);
},

@@ -173,3 +172,3 @@ message: 'by.partialButtonText("' + searchText + '")'

return driver.findElements(
webdriver.By.js(clientSideScripts.findTextareas), using, model);
webdriver.By.js(clientSideScripts.findTextareas), model, using);
},

@@ -204,3 +203,3 @@ message: 'by.textarea("' + model + '")'

webdriver.By.js(clientSideScripts.findAllRepeaterRows),
using, repeatDescriptor);
repeatDescriptor, using);
},

@@ -213,3 +212,3 @@ message: 'by.repeater("' + repeatDescriptor + '")',

webdriver.By.js(clientSideScripts.findRepeaterRows),
using, repeatDescriptor, index);
repeatDescriptor, index, using);
},

@@ -222,3 +221,3 @@ message: 'by.repeater(' + repeatDescriptor + '").row("' + index + '")"',

webdriver.By.js(clientSideScripts.findRepeaterElement),
using, repeatDescriptor, index, binding);
repeatDescriptor, index, binding, using);
},

@@ -236,3 +235,3 @@ message: 'by.repeater("' + repeatDescriptor + '").row("' + index +

webdriver.By.js(clientSideScripts.findRepeaterColumn),
using, repeatDescriptor, binding);
repeatDescriptor, binding, using);
},

@@ -246,3 +245,3 @@ message: 'by.repeater("' + repeatDescriptor + '").column("' + binding +

webdriver.By.js(clientSideScripts.findRepeaterElement),
using, repeatDescriptor, index, binding);
repeatDescriptor, index, binding, using);
},

@@ -249,0 +248,0 @@ message: 'by.repeater("' + repeatDescriptor + '").column("' +

@@ -19,3 +19,3 @@ var url = require('url');

*/
for (foo in webdriver) {
for (var foo in webdriver) {
exports[foo] = webdriver[foo];

@@ -64,3 +64,3 @@ }

return base;
}
};

@@ -455,3 +455,3 @@ /**

return originalFns[name].apply(element, arguments);
}
};
});

@@ -473,3 +473,3 @@

return this.findElement(locator);
}
};

@@ -504,3 +504,3 @@ /**

return this.findElements(locator);
}
};

@@ -529,3 +529,3 @@ /**

});
}
};

@@ -649,2 +649,12 @@ /**

/**
* Remove a registered mock module.
* @param {!string} name The name of the module to remove.
*/
Protractor.prototype.removeMockModule = function (name) {
var index = this.moduleNames_.indexOf(name);
this.moduleNames_.splice(index, 1);
this.moduleScripts_.splice(index, 1);
};
/**
* See webdriver.WebDriver.get

@@ -744,3 +754,3 @@ *

var clientSideScriptsList = [];
for (script in clientSideScripts) {
for (var script in clientSideScripts) {
clientSideScriptsList.push(

@@ -751,3 +761,3 @@ script + ': ' + clientSideScripts[script].toString());

this.driver.executeScript(
'window.clientSideScripts = {' + clientSideScriptsList.join(', ') + '}')
'window.clientSideScripts = {' + clientSideScriptsList.join(', ') + '}');

@@ -819,3 +829,3 @@ var flow = webdriver.promise.controlFlow();

return instance;
}
};

@@ -842,2 +852,2 @@ /**

return lines.join('\n');
}
};

@@ -1,216 +0,205 @@

'use strict';
var protractor = require('./protractor'),
webdriver = require('selenium-webdriver'),
ConfigParser = require('./configParser'),
path = require('path'),
util = require('util'),
fs = require('fs'),
q = require('q');
var util = require('util');
var path = require('path');
var fs = require('fs');
var webdriver = require('selenium-webdriver');
var remote = require('selenium-webdriver/remote');
var chrome = require('selenium-webdriver/chrome');
var protractor = require('./protractor.js');
var SauceLabs = require('saucelabs');
var glob = require('glob');
/*
* Runner is responsible for starting the execution of a test run and triggering
* setup, teardown, managing config, etc through its various dependencies.
*
* @param {Object} config
* @constructor
*/
var Runner = function(config) {
this.preparers_ = [];
this.driverprovider_ = null;
this.config_ = config;
var server;
var driver;
var sessionId;
var sauceAccount;
// Default configuration.
var config = {
configDir: './',
seleniumServerJar: null,
seleniumArgs: [],
seleniumPort: null,
seleniumAddress: null,
allScriptsTimeout: 11000,
capabilities: {
'browserName': 'chrome'
},
rootElement: 'body',
params: {},
framework: 'jasmine',
jasmineNodeOpts: {
isVerbose: false,
showColors: true,
includeStackTrace: true,
stackFilter: protractor.filterStackTrace
},
mochaOpts: {
ui: 'bdd',
reporter: 'list'
}
// Init
this.loadDriverProvider_(config);
};
/**
* Merge config objects together.
* Execute the Runner's test cases through Jasmine.
*
* @param {Object} into
* @param {Object} from
*
* @return {Object} The 'into' config.
* @private
* @param {Array} specs Array of Directory Path Strings
* @param done A callback for when tests are finished.
*/
var merge = function(into, from) {
for (var key in from) {
if (into[key] instanceof Object && !(into[key] instanceof Array)) {
merge(into[key], from[key]);
} else {
into[key] = from[key];
}
}
return into;
Runner.prototype.runJasmine_ = function(specs, done) {
var minijn = require('minijasminenode'),
self = this;
require('../jasminewd');
webdriver.promise.controlFlow().execute(function() {
self.runTestPreparers_();
}).then(function() {
var jasmineNodeOpts = self.config_.jasmineNodeOpts;
var originalOnComplete = self.config_.onComplete;
jasmineNodeOpts.onComplete = function(runner, log) {
if (originalOnComplete) {
originalOnComplete(runner, log);
}
done(runner.results());
};
minijn.addSpecs(specs);
minijn.executeSpecs(jasmineNodeOpts);
});
};
/**
* Add the options in the parameter config to this runner instance.
* Execute the Runner's test cases through Mocha.
*
* @param {Object} additionalConfig
* @private
* @param {Array} specs Array of Directory Path Strings
* @param done A callback for when tests are finished.
*/
var addConfig = function(additionalConfig) {
// All filepaths should be kept relative to the current config location.
// This will not affect absolute paths.
['seleniumServerJar', 'chromeDriver', 'onPrepare'].forEach(function(name) {
if (additionalConfig[name] && additionalConfig.configDir &&
typeof additionalConfig[name] === 'string') {
additionalConfig[name] =
path.resolve(additionalConfig.configDir, additionalConfig[name]);
}
})
merge(config, additionalConfig);
};
Runner.prototype.runMocha_ = function(specs, done) {
/**
* Cleanup the driver and server after running tests.
*
* @param runner The Jasmine runner object.
*/
var cleanUp = function(runner) {
var passed = runner.results().failedCount === 0;
var exitCode = passed ? 0 : 1;
var exit = function(exitCode) {
if (typeof config.onCleanUp === 'function') {
config.onCleanUp(exitCode);
}
process.exit(exitCode);
};
if (sauceAccount) {
sauceAccount.updateJob(sessionId, {'passed': passed}, function(err) {
if (err) {
throw new Error(
'Error updating Sauce pass/fail status: ' + util.inspect(err)
);
var Mocha = require('mocha'),
mocha = new Mocha(this.config_.mochaOpts),
self = this;
// Mocha doesn't set up the ui until the pre-require event, so
// wait until then to load mocha-webdriver adapters as well.
mocha.suite.on('pre-require', function() {
var mochaAdapters = require('selenium-webdriver/testing');
global.after = mochaAdapters.after;
global.afterEach = mochaAdapters.afterEach;
global.before = mochaAdapters.before;
global.beforeEach = mochaAdapters.beforeEach;
global.it = mochaAdapters.it;
global.it.only = global.iit = mochaAdapters.it.only;
global.it.skip = global.xit = mochaAdapters.xit;
});
mocha.loadFiles();
webdriver.promise.controlFlow().execute(function() {
self.runTestPreparers_();
}).then(function() {
specs.forEach(function(file) {
mocha.addFile(file);
});
mocha.run(function(failures) {
if (self.config_.onComplete) {
self.config_.onComplete();
}
exit(exitCode);
var resolvedObj = {
failedCount: failures
};
done(resolvedObj);
});
} else if (server) {
util.puts('Shutting down selenium standalone server.');
server.stop().then(function() {
exit(exitCode);
});
} else {
exit(exitCode);
}
});
};
/**
* Sets up the Selenium server and returns a promise once the server is
* ready to go. After this function is called, config.seleniumAddress
* and config.capabilities are set up.
* Execute the Runner's test cases through Cucumber.
*
* @return {webdriver.promise.Promise.<string>} A promise which resolves to
* the value of the selenium address that will be used.
* @private
* @param {Array} specs Array of Directory Path Strings
* @param done A callback for when tests are finished.
*/
var setUpSelenium = function() {
// TODO: This should not be tied to the webdriver promise loop, it should use
// another promise system instead.
var deferred = webdriver.promise.defer();
Runner.prototype.runCucumber_ = function(specs, done) {
var Cucumber = require('cucumber'),
self = this,
execOptions = ['node', 'node_modules/.bin/cucumber-js'],
cucumberResolvedRequire;
if (config.sauceUser && config.sauceKey) {
sauceAccount = new SauceLabs({
username: config.sauceUser,
password: config.sauceKey
});
}
// Set up exec options for Cucumber
execOptions = execOptions.concat(specs);
if (self.config_.cucumberOpts) {
var defaultChromedriver;
if (config.chromeDriver) {
if (!fs.existsSync(config.chromeDriver)) {
if (fs.existsSync(config.chromeDriver + '.exe')) {
config.chromeDriver += '.exe';
} else {
throw 'Could not find chromedriver at ' + config.chromeDriver;
// Process Cucumber Require param
if (self.config_.cucumberOpts.require) {
cucumberResolvedRequire =
ConfigParser.resolveFilePatterns(self.config_.cucumberOpts.require);
if (cucumberResolvedRequire && cucumberResolvedRequire.length) {
execOptions.push('-r');
execOptions = execOptions.concat(cucumberResolvedRequire);
}
}
} else {
defaultChromedriver = path.resolve(
__dirname,
'../selenium/chromedriver');
if (fs.existsSync(defaultChromedriver)) {
config.chromeDriver = defaultChromedriver;
} else if (fs.existsSync(defaultChromedriver + '.exe')) {
config.chromeDriver = defaultChromedriver + '.exe';
// Process Cucumber Tag param
if (self.config_.cucumberOpts.tags) {
execOptions.push('-t');
execOptions.push(self.config_.cucumberOpts.tags);
}
}
// Priority
// 1) if chromeOnly, use that
// 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
if (config.chromeOnly) {
util.puts('Using ChromeDriver directly...');
deferred.fulfill(null);
} else if (config.seleniumAddress) {
util.puts('Using the selenium server at ' + config.seleniumAddress);
deferred.fulfill(config.seleniumAddress);
} else if (sauceAccount) {
config.capabilities.username = config.sauceUser;
config.capabilities.accessKey = config.sauceKey;
if (!config.jasmineNodeOpts.defaultTimeoutInterval) {
config.jasmineNodeOpts.defaultTimeoutInterval = 30 * 1000;
// Process Cucumber Format param
if (self.config_.cucumberOpts.format) {
execOptions.push('-f');
execOptions.push(self.config_.cucumberOpts.format);
}
config.seleniumAddress = 'http://' + config.sauceUser + ':' +
config.sauceKey + '@ondemand.saucelabs.com:80/wd/hub';
}
cucumber = Cucumber.Cli(execOptions);
util.puts('Using SauceLabs selenium server at ' + config.seleniumAddress);
deferred.fulfill(config.seleniumAddress);
} else {
util.puts('Starting selenium standalone server...');
webdriver.promise.controlFlow().execute(function() {
self.runTestPreparers_();
}).then(function() {
if (!config.seleniumServerJar) {
// Try to use the default location.
var defaultStandalone = path.resolve(__dirname,
'../selenium/selenium-server-standalone-' +
require('../package.json').webdriverVersions.selenium + '.jar');
if (!fs.existsSync(defaultStandalone)) {
throw new Error('Unable to start selenium. ' +
'You must specify either a seleniumAddress, ' +
'seleniumServerJar, or saucelabs account, or use webdriver-manager.');
cucumber.run(function(succeeded) {
if (self.config_.onComplete) {
self.config_.onComplete();
}
var resolvedObj = {
failedCount: succeeded ? 0 : 1
};
done(resolvedObj);
});
});
};
/**
* Internal helper for abstraction of polymorphic filenameOrFn properties.
* @private
* @param {Array} source The Array that we'll be iterating through
* as we evaluate whether to require or execute each item.
*/
Runner.prototype.runFilenamesOrFns_ = function(source) {
var filenameOrFn;
for (var i = 0; i < source.length; i++) {
filenameOrFn = source[i];
if (filenameOrFn) {
if (typeof filenameOrFn === 'function') {
filenameOrFn();
} else if (typeof filenameOrFn === 'string') {
require(path.resolve(this.config_.configDir, filenameOrFn));
} else {
config.seleniumServerJar = defaultStandalone;
// TODO - this is not generic.
throw 'config.onPrepare must be a string or function';
}
} else if (!fs.existsSync(config.seleniumServerJar)) {
throw new Error('there\'s no selenium server jar at the specified ' +
'location. Do you have the correct version?');
}
}
};
if (config.chromeDriver) {
config.seleniumArgs.push(
'-Dwebdriver.chrome.driver=' + config.chromeDriver);
}
server = new remote.SeleniumServer(config.seleniumServerJar, {
args: config.seleniumArgs,
port: config.seleniumPort
});
/**
* Registrar for testPreparers - executed right before tests run.
* @public
* @param {string/Fn} filenameOrFn
*/
Runner.prototype.registerTestPreparer = function(filenameOrFn) {
this.preparers_.push(filenameOrFn);
};
server.start().then(function(url) {
util.puts('Selenium standalone server started at ' + url);
config.seleniumAddress = server.address();
deferred.fulfill(config.seleniumAddress);
});
}
return deferred.promise;
/**
* Executor of testPreparers
* @private
*/
Runner.prototype.runTestPreparers_ = function() {
this.runFilenamesOrFns_(this.preparers_);
};

@@ -220,189 +209,164 @@

/**
* Resolve a list of file patterns into a list of individual file paths.
* Grab driver provider based on type
* @private
*
* @param {array} patterns
* @param {boolean} opt_omitWarnings whether to omit did not match warnings
*
* @return {array} The resolved file paths.
* Priority
* 1) if chromeOnly, use that
* 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
*/
var resolveFilePatterns = function(patterns, opt_omitWarnings) {
var resolvedFiles = [];
Runner.prototype.loadDriverProvider_ = function() {
var runnerPath;
if (this.config_.chromeOnly) {
runnerPath = './driverProviders/chrome.dp';
} else if (this.config_.seleniumAddress) {
runnerPath = './driverProviders/hosted.dp';
} else if (this.config_.sauceUser && this.config_.sauceKey) {
runnerPath = './driverProviders/sauce.dp';
} else if (this.config_.seleniumServerJar) {
runnerPath = './driverProviders/local.dp';
} else {
runnerPath = './driverProviders/local.dp';
}
if (patterns) {
for (var i = 0; i < patterns.length; ++i) {
var matches = glob.sync(patterns[i], {cwd: config.configDir});
if (!matches.length && !opt_omitWarnings) {
util.puts('Warning: pattern ' + patterns[i] + ' did not match any files.');
}
for (var j = 0; j < matches.length; ++j) {
resolvedFiles.push(path.resolve(config.configDir, matches[j]));
}
}
this.driverprovider_ = require(runnerPath)(this.config_);
};
/**
* Responsible for cleaning up test run and exiting the process.
* @private
* @param {int} Standard unix exit code
*/
Runner.prototype.exit_ = function(exitCode) {
if (typeof this.config_.onCleanUp === 'function') {
this.config_.onCleanUp(exitCode);
}
return resolvedFiles;
};
/**
* Set up webdriver and run the tests. Note that due to the current setup of
* loading Jasmine and the test specs, this should only be run once.
* Getter for the Runner config object
* @public
* @return {Object} config
*/
Runner.prototype.getConfig = function() {
return this.config_;
};
/**
* Sets up convenience globals for test specs
* @private
*/
Runner.prototype.setupGlobals_ = function(driver) {
var browser = protractor.wrapDriver(
driver,
this.config_.baseUrl,
this.config_.rootElement);
browser.params = this.config_.params;
protractor.setInstance(browser);
// Export protractor to the global namespace to be used in tests.
global.protractor = protractor;
global.browser = browser;
global.$ = browser.$;
global.$$ = browser.$$;
global.element = browser.element;
global.by = global.By = protractor.By;
};
/**
* The primary workhorse interface. Kicks off the test running process.
*
* @return {webdriver.promise.Promise} A promise that will resolve
* when the test run is finished.
* @public
*/
var runTests = function() {
if (config.jasmineNodeOpts.specFolders) {
throw new Error('Using config.jasmineNodeOpts.specFolders is deprecated ' +
'since Protractor 0.6.0. Please switch to config.specs.');
}
Runner.prototype.run = function() {
var self = this,
driver,
specs,
excludes,
testResult;
var resolvedExcludes = resolveFilePatterns(config.exclude, true);
var resolvedSpecs = resolveFilePatterns(config.specs).filter(function (path) {
return resolvedExcludes.indexOf(path) < 0;
// 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) {
return excludes.indexOf(path) < 0;
});
if (!resolvedSpecs.length) {
if (!specs.length) {
throw new Error('Spec patterns did not match any files.');
}
// TODO: This should not be tied to the webdriver promise loop, it should use
// another promise system instead.
var runDeferred = webdriver.promise.defer();
this.registerTestPreparer(this.config_.onPrepare);
if (config.chromeOnly) {
var service = new chrome.ServiceBuilder(config.chromeDriver).build();
driver = chrome.createDriver(
new webdriver.Capabilities(config.capabilities), service);
} else {
driver = new webdriver.Builder().
usingServer(config.seleniumAddress).
withCapabilities(config.capabilities).build();
}
// 1) Setup environment
return this.driverprovider_.setupEnv().then(function() {
driver = self.driverprovider_.getDriver();
return q.fcall(function() {});
driver.getSession().then(function(session) {
driver.manage().timeouts().setScriptTimeout(config.allScriptsTimeout);
// 2) Execute test cases
}).then(function() {
sessionId = session.getId();
var deferred = q.defer();
driver.manage().timeouts().setScriptTimeout(self.config_.allScriptsTimeout);
self.setupGlobals_.bind(self)(driver);
var browser = protractor.wrapDriver(
driver,
config.baseUrl,
config.rootElement);
browser.params = config.params;
protractor.setInstance(browser);
// Export protractor to the global namespace to be used in tests.
global.protractor = protractor;
global.browser = browser;
global.$ = browser.$;
global.$$ = browser.$$;
global.element = browser.element;
global.by = global.By = protractor.By;
// Do the framework setup here so that jasmine and mocha globals are
// available to the onPrepare function.
var minijn, mocha;
if (config.framework === 'jasmine') {
minijn = require('minijasminenode');
require('../jasminewd');
minijn.addSpecs(resolvedSpecs);
} else if (config.framework === 'mocha') {
var Mocha = require('mocha');
mocha = new Mocha(config.mochaOpts);
resolvedSpecs.forEach(function(file) {
mocha.addFile(file);
if (self.config_.framework === 'jasmine') {
self.runJasmine_.bind(self)(specs, function(result) {
deferred.resolve(result);
});
// Mocha doesn't set up the ui until the pre-require event, so
// wait until then to load mocha-webdriver adapters as well.
mocha.suite.on('pre-require', function() {
var mochaAdapters = require('selenium-webdriver/testing');
global.after = mochaAdapters.after;
global.afterEach = mochaAdapters.afterEach;
global.before = mochaAdapters.before;
global.beforeEach = mochaAdapters.beforeEach;
global.it = mochaAdapters.it;
global.it.only = global.iit = mochaAdapters.it.only;
global.it.skip = global.xit = mochaAdapters.xit;
} else if (self.config_.framework === 'mocha') {
self.runMocha_.bind(self)(specs, function(result) {
deferred.resolve(result);
});
mocha.loadFiles();
} else if (self.config_.framework === 'cucumber') {
self.runCucumber_.bind(self)(specs, function(result) {
deferred.resolve(result);
});
} else if (self.config_.framework === 'simpleprint') {
console.log('Resolved spec files ' + util.inspect(specs));
deferred.resolve({failedCount: 0});
} else {
throw 'config.framework ' + config.framework +
' is not a valid framework.';
throw new Error('config.framework (' + self.config_.framework +
') is not a valid framework.');
}
return deferred.promise;
// Let the configuration configure the protractor instance before running
// the tests.
webdriver.promise.controlFlow().execute(function() {
if (config.onPrepare) {
if (typeof config.onPrepare === 'function') {
config.onPrepare();
} else if (typeof config.onPrepare === 'string') {
require(path.resolve(config.configDir, config.onPrepare));
} else {
throw 'config.onPrepare must be a string or function';
}
}
}).then(function() {
var options = config.jasmineNodeOpts;
var originalOnComplete = options.onComplete;
options.onComplete = function(runner, log) {
if (originalOnComplete) {
originalOnComplete(runner, log);
}
driver.quit().then(function() {
runDeferred.fulfill(runner);
});
};
if (config.framework === 'jasmine') {
minijn.executeSpecs(options);
} else if (config.framework === 'mocha') {
mocha.run(function(failures) {
// Warning: hack to make it have the same signature as Jasmine 1.3.1.
if (originalOnComplete) {
originalOnComplete();
}
driver.quit().then(function() {
runDeferred.fulfill({
results: function() {
return {
failedCount: failures
};
}
});
// 3) Teardown
}).then(function(result) {
testResult = result;
if (self.driverprovider_.updateJob) {
return self.driverprovider_.updateJob({
'passed': testResult.failedCount === 0
}).then(function() {
return self.driverprovider_.teardownEnv();
});
});
}
});
} else {
return self.driverprovider_.teardownEnv();
}
// 4) Exit process
}).then(function() {
var passed = testResult.failedCount === 0;
var exitCode = passed ? 0 : 1;
self.exit_(exitCode);
return exitCode;
});
return runDeferred.promise;
};
/**
* Run Protractor once.
* Creates and returns a Runner instance
*
* @public
* @param {Object} config
*/
var runOnce = function() {
var specs = config.specs;
if (!specs || specs.length === 0) {
util.puts('No spec files found');
process.exit(0);
}
return setUpSelenium().then(function() {
// cleanUp must be registered directly onto runTests, not onto
// the chained promise, so that cleanUp is still called in case of a
// timeout error. Timeout errors need to clear the control flow, which
// would mess up chaining promises.
return runTests().then(cleanUp);
});
};
exports.addConfig = addConfig;
exports.runOnce = runOnce;
module.exports = Runner;

@@ -20,3 +20,4 @@ {

"adm-zip": ">=0.4.2",
"optimist": "~0.6.0"
"optimist": "~0.6.0",
"q": "1.0.0"
},

@@ -29,2 +30,3 @@ "devDependencies": {

"mocha": "~1.16.0",
"cucumber": "~0.3.3",
"express": "~3.3.4",

@@ -43,11 +45,11 @@ "mustache": "~0.7.2"

"scripts": {
"test": "node lib/cli.js spec/basicConf.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/withLoginConf.js; node_modules/.bin/minijasminenode jasminewd/spec/adapterSpec.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"
},
"license" : "MIT",
"version": "0.18.1",
"version": "0.19.0",
"webdriverVersions": {
"selenium": "2.39.0",
"chromedriver": "2.8",
"chromedriver": "2.9",
"iedriver": "2.39.0"
}
}

@@ -72,2 +72,7 @@ // A reference configuration file.

// If you would like to run more than one instance of webdriver on the same
// tests, use multiCapabilities, which takes an array of capabilities.
// If this is specified, capabilities will be ignored.
multiCapabilities: [],
// ----- More information for your tests ----

@@ -108,3 +113,3 @@ //

//
// Jasmine is fully supported as a test and assertion framework.
// Jasmine and Cucumber are fully supported as a test and assertion framework.
// Mocha has limited beta support. You will need to include your own

@@ -138,2 +143,12 @@ // assertion framework if working with mocha.

// ----- Options to be passed to cucumber -----
cucumberOpts: {
// Require files before executing the features.
require: 'cucumber/stepDefinitions.js',
// Only execute the features or scenarios with tags matching @dev.
tags: '@dev',
// How to format features (default: progress)
format: 'summary'
},
// ----- The cleanup step -----

@@ -140,0 +155,0 @@ //

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc