Socket
Socket
Sign inDemoInstall

protractor

Package Overview
Dependencies
Maintainers
2
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 4.0.10 to 4.0.11

.idea/codeStyleSettings.xml

11

built/browser.d.ts

@@ -149,3 +149,7 @@ /// <reference types="selenium-webdriver" />

*/
mockModules_: any[];
mockModules_: {
name: string;
script: string | Function;
args: any[];
}[];
/**

@@ -269,4 +273,3 @@ * If specified, start a debugger server at specified port instead of repl

* so any module registered here will override preexisting modules with the
* same
* name.
* same name.
*

@@ -327,3 +330,3 @@ * @example

*/
get(destination: string, opt_timeout?: number): any;
get(destination: string, timeout?: number): wdpromise.Promise<void>;
/**

@@ -330,0 +333,0 @@ * @see webdriver.WebDriver.refresh

@@ -17,2 +17,3 @@ "use strict";

var webdriver = require('selenium-webdriver');
// TODO: fix the typings for selenium-webdriver/lib/command
var Command = require('selenium-webdriver/lib/command').Command;

@@ -103,6 +104,4 @@ var CommandName = require('selenium-webdriver/lib/command').Name;

// Mix all other driver functionality into Protractor.
Object.getOwnPropertyNames(webdriver.WebDriver.prototype)
.forEach(function (method) {
if (!_this[method] &&
typeof webdriverInstance[method] == 'function') {
Object.getOwnPropertyNames(selenium_webdriver_1.WebDriver.prototype).forEach(function (method) {
if (!_this[method] && typeof webdriverInstance[method] === 'function') {
if (methodsToSync.indexOf(method) !== -1) {

@@ -118,4 +117,4 @@ ptorMixin(_this, webdriverInstance, method, _this.waitForAngular.bind(_this));

this.element = buildElementHelper(this);
this.$ = element_1.build$(this.element, webdriver.By);
this.$$ = element_1.build$$(this.element, webdriver.By);
this.$ = element_1.build$(this.element, selenium_webdriver_1.By);
this.$$ = element_1.build$$(this.element, selenium_webdriver_1.By);
this.baseUrl = opt_baseUrl || '';

@@ -261,3 +260,3 @@ this.rootEl = opt_rootElement || 'body';

if (_this.plugins_.skipAngularStability()) {
return webdriver.promise.fulfilled();
return selenium_webdriver_1.promise.fulfilled();
}

@@ -286,5 +285,3 @@ else if (_this.rootEl) {

return _this.plugins_.waitForCondition().then(function (results) {
return results.reduce(function (x, y) {
return x && y;
}, true);
return results.reduce(function (x, y) { return x && y; }, true);
});

@@ -308,13 +305,12 @@ }, _this.allScriptsTimeout, 'Plugins.waitForCondition()');

if (timeout) {
var errMsg_1 = 'Timed out waiting for Protractor to synchronize with ' +
'the page after ' + timeout + '. Please see ' +
'https://github.com/angular/protractor/blob/master/docs/faq.md';
var errMsg_1 = "Timed out waiting for asynchronous Angular tasks to finish after " +
(timeout + ". This may be because the current page is not an Angular ") +
"application. Please see the FAQ for more details: " +
"https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular";
if (description.indexOf(' - Locator: ') == 0) {
errMsg_1 +=
'\nWhile waiting for element with locator' + description;
errMsg_1 += '\nWhile waiting for element with locator' + description;
}
var pendingTimeoutsPromise = void 0;
if (_this.trackOutstandingTimeouts_) {
pendingTimeoutsPromise = _this.executeScriptWithDescription('return window.NG_PENDING_TIMEOUTS', 'Protractor.waitForAngular() - getting pending timeouts' +
description);
pendingTimeoutsPromise = _this.executeScriptWithDescription('return window.NG_PENDING_TIMEOUTS', 'Protractor.waitForAngular() - getting pending timeouts' + description);
}

@@ -324,6 +320,4 @@ else {

}
var pendingHttpsPromise = _this.executeScriptWithDescription(clientSideScripts.getPendingHttpRequests, 'Protractor.waitForAngular() - getting pending https' +
description, _this.rootEl);
return selenium_webdriver_1.promise
.all([pendingTimeoutsPromise, pendingHttpsPromise])
var pendingHttpsPromise = _this.executeScriptWithDescription(clientSideScripts.getPendingHttpRequests, 'Protractor.waitForAngular() - getting pending https' + description, _this.rootEl);
return selenium_webdriver_1.promise.all([pendingTimeoutsPromise, pendingHttpsPromise])
.then(function (arr) {

@@ -382,5 +376,3 @@ var pendingTimeouts = arr[0] || [];

ProtractorBrowser.prototype.isElementPresent = function (locatorOrElement) {
var element = (locatorOrElement.isPresent) ?
locatorOrElement :
this.element(locatorOrElement);
var element = (locatorOrElement.isPresent) ? locatorOrElement : this.element(locatorOrElement);
return element.isPresent();

@@ -392,4 +384,3 @@ };

* so any module registered here will override preexisting modules with the
* same
* name.
* same name.
*

@@ -443,5 +434,3 @@ * @example

ProtractorBrowser.prototype.getRegisteredMockModules = function () {
return this.mockModules_.map(function (module) {
return module.script;
});
return this.mockModules_.map(function (module) { return module.script; });
};

@@ -473,7 +462,6 @@ ;

*/
ProtractorBrowser.prototype.get = function (destination, opt_timeout) {
ProtractorBrowser.prototype.get = function (destination, timeout) {
var _this = this;
var timeout = opt_timeout ? opt_timeout : this.getPageTimeout;
destination = this.baseUrl.indexOf('file://') === 0 ?
this.baseUrl + destination :
if (timeout === void 0) { timeout = this.getPageTimeout; }
destination = this.baseUrl.indexOf('file://') === 0 ? this.baseUrl + destination :
url.resolve(this.baseUrl, destination);

@@ -485,7 +473,5 @@ var msg = function (str) {

this.driver.get(destination);
return this.driver.controlFlow().execute(function () {
return _this.plugins_.onPageLoad();
});
return this.driver.controlFlow().execute(function () { return _this.plugins_.onPageLoad(); }).then(function () { });
}
var deferred = webdriver.promise.defer();
var deferred = selenium_webdriver_1.promise.defer();
this.driver.get(this.resetUrl).then(null, deferred.reject);

@@ -528,4 +514,6 @@ this.executeScriptWithDescription('window.name = "' + DEFER_LABEL + '" + window.name;' +

var message = angularTestResult.message;
throw new Error('Angular could not be found on the page ' + destination +
' : ' + message);
logger.error("Could not find Angular on page " + destination + " : " + message);
throw new Error(("Angular could not be found on the page " + destination + ". If this is not an ") +
"Angular application, you may need to turn off waiting for Angular. Please " +
"see https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular-on-page-load");
}

@@ -540,22 +528,16 @@ return angularVersion;

if (angularVersion === 1) {
// At this point, Angular will pause for us until
// angular.resumeBootstrap
// is called.
// At this point, Angular will pause for us until angular.resumeBootstrap is called.
var moduleNames = [];
var _loop_1 = function(i) {
var mockModule = self.mockModules_[i];
var name_1 = mockModule.name;
var _loop_1 = function(name_1, script, args) {
moduleNames.push(name_1);
var executeScriptArgs = [
mockModule.script, msg('add mock module ' + name_1)
].concat(mockModule.args);
var executeScriptArgs = [script, msg('add mock module ' + name_1)].concat(args);
self.executeScriptWithDescription.apply(self, executeScriptArgs)
.then(null, function (err) {
throw new Error('Error while running module script ' + name_1 + ': ' +
err.message);
throw new Error('Error while running module script ' + name_1 + ': ' + err.message);
})
.then(null, deferred.reject);
};
for (var i = 0; i < self.mockModules_.length; ++i) {
_loop_1(i);
for (var _i = 0, _a = self.mockModules_; _i < _a.length; _i++) {
var _b = _a[_i], name_1 = _b.name, script = _b.script, args = _b.args;
_loop_1(name_1, script, args);
}

@@ -575,7 +557,5 @@ self.executeScriptWithDescription('angular.resumeBootstrap(arguments[0]);', msg('resume bootstrap'), moduleNames)

this.driver.controlFlow().execute(function () {
return self.plugins_.onPageStable().then(function () {
return _this.plugins_.onPageStable().then(function () {
deferred.fulfill();
}, function (error) {
deferred.reject(error);
});
}, deferred.reject);
});

@@ -633,4 +613,3 @@ return deferred.promise;

if (browserErr) {
throw 'Error while navigating to \'' + url + '\' : ' +
JSON.stringify(browserErr);
throw 'Error while navigating to \'' + url + '\' : ' + JSON.stringify(browserErr);
}

@@ -676,3 +655,3 @@ });

this.driver.executeScript(clientSideScripts.installInBrowser);
webdriver.promise.controlFlow().execute(function () {
selenium_webdriver_1.promise.controlFlow().execute(function () {
debugger;

@@ -733,3 +712,3 @@ }, 'add breakpoint to control flow');

logger.info('Encountered browser.pause(), but debugger already attached.');
return webdriver.promise.fulfilled(true);
return selenium_webdriver_1.promise.fulfilled(true);
}

@@ -736,0 +715,0 @@ var debuggerClientPath = __dirname + '/debugger/clients/wddebugger.js';

@@ -0,1 +1,2 @@

import { PluginConfig } from './plugins';
export interface Config {

@@ -29,2 +30,8 @@ /**

args?: any;
/**
* Additional command line jvm options to pass to selenium. For example,
* if you need to change the browser driver, use
* jvmArgs: ['-Dwebdriver.ie.driver=IEDriverServer_Win32_2.53.1.exe']
*/
jvmArgs?: string[];
};

@@ -433,2 +440,10 @@ /**

invertGrep?: boolean;
/**
* If true, run specs in semi-random order
*/
random?: boolean;
/**
* Set the randomization seed if randomization is turned on
*/
seed?: string;
};

@@ -470,3 +485,3 @@ /**

*/
plugins?: Array<any>;
plugins?: PluginConfig[];
/**

@@ -492,2 +507,3 @@ * Turns off source map support. Stops protractor from registering global

seleniumArgs?: Array<any>;
jvmArgs?: string[];
configDir?: string;

@@ -494,0 +510,0 @@ troubleshoot?: boolean;

@@ -105,9 +105,5 @@ "use strict";

// This will not affect absolute paths.
['seleniumServerJar', 'chromeDriver', 'onPrepare', 'firefoxPath',
'frameworkPath']
.forEach(function (name) {
if (additionalConfig[name] &&
typeof additionalConfig[name] === 'string') {
additionalConfig[name] =
path.resolve(relativeTo, additionalConfig[name]);
['seleniumServerJar', 'chromeDriver', 'onPrepare', 'firefoxPath', 'frameworkPath'].forEach(function (name) {
if (additionalConfig[name] && typeof additionalConfig[name] === 'string') {
additionalConfig[name] = path.resolve(relativeTo, additionalConfig[name]);
}

@@ -114,0 +110,0 @@ });

@@ -61,4 +61,3 @@ "use strict";

process['debugPort'] = opt_debugPort || process['debugPort'];
_this.validatePortAvailability_(process['debugPort'])
.then(function (firstTime) {
_this.validatePortAvailability_(process['debugPort']).then(function (firstTime) {
onStartFn(firstTime);

@@ -221,4 +220,3 @@ var args = [process.pid, process['debugPort']];

else {
doneDeferred.reject('Unexpected failure testing for port ' + port + ': ' +
JSON.stringify(err));
doneDeferred.reject('Unexpected failure testing for port ' + port + ': ' + JSON.stringify(err));
}

@@ -225,0 +223,0 @@ });

@@ -38,4 +38,3 @@ "use strict";

'Authorization': 'Basic ' +
new Buffer(_this.config_.browserstackUser + ':' +
_this.config_.browserstackKey)
new Buffer(_this.config_.browserstackUser + ':' + _this.config_.browserstackKey)
.toString('base64')

@@ -53,6 +52,4 @@ };

var info = JSON.parse(data.toString());
if (info && info.automation_session &&
info.automation_session.browser_url) {
logger.info('BrowserStack results available at ' +
info.automation_session.browser_url);
if (info && info.automation_session && info.automation_session.browser_url) {
logger.info('BrowserStack results available at ' + info.automation_session.browser_url);
}

@@ -82,4 +79,3 @@ else {

res.on('error', function (e) {
throw new exitCodes_1.BrowserError(logger, 'Error updating BrowserStack pass/fail status: ' +
util.inspect(e));
throw new exitCodes_1.BrowserError(logger, 'Error updating BrowserStack pass/fail status: ' + util.inspect(e));
});

@@ -102,16 +98,12 @@ });

var deferred = q.defer();
this.config_.capabilities['browserstack.user'] =
this.config_.browserstackUser;
this.config_.capabilities['browserstack.key'] =
this.config_.browserstackKey;
this.config_.capabilities['browserstack.user'] = this.config_.browserstackUser;
this.config_.capabilities['browserstack.key'] = this.config_.browserstackKey;
this.config_.seleniumAddress = 'http://hub.browserstack.com/wd/hub';
// Append filename to capabilities.name so that it's easier to identify
// tests.
if (this.config_.capabilities.name &&
this.config_.capabilities.shardTestFiles) {
if (this.config_.capabilities.name && this.config_.capabilities.shardTestFiles) {
this.config_.capabilities.name +=
(':' + this.config_.specs.toString().replace(/^.*[\\\/]/, ''));
}
logger.info('Using BrowserStack selenium server at ' +
this.config_.seleniumAddress);
logger.info('Using BrowserStack selenium server at ' + this.config_.seleniumAddress);
deferred.resolve();

@@ -118,0 +110,0 @@ return deferred.promise;

@@ -72,4 +72,3 @@ "use strict";

if (this.config_.firefoxPath) {
this.config_.capabilities['firefox_binary'] =
this.config_.firefoxPath;
this.config_.capabilities['firefox_binary'] = this.config_.firefoxPath;
}

@@ -76,0 +75,0 @@ driver = new firefox.Driver(this.config_.capabilities);

@@ -81,2 +81,5 @@ "use strict";

}
if (serverConf.jvmArgs === undefined) {
serverConf.jvmArgs = this.config_.jvmArgs || [];
}
if (serverConf.port === undefined) {

@@ -87,6 +90,5 @@ serverConf.port = this.config_.seleniumPort;

if (this.config_.chromeDriver) {
serverConf.args.push('-Dwebdriver.chrome.driver=' + this.config_.chromeDriver);
serverConf.jvmArgs.push('-Dwebdriver.chrome.driver=' + this.config_.chromeDriver);
}
this.server_ =
new remote.SeleniumServer(this.config_.seleniumServerJar, serverConf);
this.server_ = new remote.SeleniumServer(this.config_.seleniumServerJar, serverConf);
// start local server, grab hosted address, and resolve promise

@@ -93,0 +95,0 @@ this.server_.start().then(function (url) {

@@ -34,4 +34,3 @@ /*

driver.getSession().then(function (session) {
logger.info('SauceLabs results available at http://saucelabs.com/jobs/' +
session.getId());
logger.info('SauceLabs results available at http://saucelabs.com/jobs/' + session.getId());
_this.sauceServer_.updateJob(session.getId(), update, function (err) {

@@ -67,9 +66,7 @@ if (err) {

this.config_.seleniumAddress =
auth + (this.config_.sauceSeleniumAddress ?
this.config_.sauceSeleniumAddress :
auth + (this.config_.sauceSeleniumAddress ? this.config_.sauceSeleniumAddress :
'ondemand.saucelabs.com:80/wd/hub');
// Append filename to capabilities.name so that it's easier to identify
// tests.
if (this.config_.capabilities.name &&
this.config_.capabilities.shardTestFiles) {
if (this.config_.capabilities.name && this.config_.capabilities.shardTestFiles) {
this.config_.capabilities.name +=

@@ -76,0 +73,0 @@ (':' + this.config_.specs.toString().replace(/^.*[\\\/]/, ''));

/// <reference types="selenium-webdriver" />
import { ILocation, ISize, promise as wdpromise, WebDriver, WebElement, WebElementPromise } from 'selenium-webdriver';
import { By, ILocation, ISize, promise as wdpromise, WebDriver, WebElement, WebElementPromise } from 'selenium-webdriver';
import { ElementHelper } from './browser';
import { ProtractorBrowser } from './browser';
import { Locator, ProtractorBy } from './locators';
import { Locator } from './locators';
export declare class WebdriverWebElement {

@@ -161,3 +161,3 @@ getDriver: () => WebDriver;

* Get an element within the ElementArrayFinder by index. The index starts at
* 0. Negative indices are wrapped (i.e. -i means ith element from last)
* 0\. Negative indices are wrapped (i.e. -i means ith element from last)
* This does not actually retrieve the underlying element.

@@ -280,3 +280,3 @@ *

*/
applyAction_(actionFn: (value: WebElement, index: number, array: WebElement[]) => any): ElementArrayFinder;
private applyAction_(actionFn);
/**

@@ -313,3 +313,3 @@ * Represents the ElementArrayFinder as an array of ElementFinders.

*/
then(fn?: (value: any) => {} | wdpromise.IThenable<{}>, errorFn?: (error: any) => any): wdpromise.Promise<any[]>;
then(fn?: (value: any) => any | wdpromise.IThenable<any>, errorFn?: (error: any) => any): wdpromise.Promise<any[]>;
/**

@@ -705,3 +705,3 @@ * Calls the input function on each ElementFinder represented by the

*/
export declare let build$: (element: ElementHelper, by: ProtractorBy) => (selector: string) => ElementFinder;
export declare let build$: (element: ElementHelper, by: typeof By) => (selector: string) => ElementFinder;
/**

@@ -732,2 +732,2 @@ * Shortcut for querying the document directly with css.

*/
export declare let build$$: (element: ElementHelper, by: ProtractorBy) => (selector: string) => ElementArrayFinder;
export declare let build$$: (element: ElementHelper, by: typeof By) => (selector: string) => ElementArrayFinder;

@@ -13,6 +13,5 @@ "use strict";

var WEB_ELEMENT_FUNCTIONS = [
'click', 'sendKeys', 'getTagName', 'getCssValue', 'getAttribute', 'getText',
'getSize', 'getLocation', 'isEnabled', 'isSelected', 'submit', 'clear',
'isDisplayed', 'getOuterHtml', 'getInnerHtml', 'getId', 'getRawId',
'serialize', 'takeScreenshot'
'click', 'sendKeys', 'getTagName', 'getCssValue', 'getAttribute', 'getText', 'getSize',
'getLocation', 'isEnabled', 'isSelected', 'submit', 'clear', 'isDisplayed', 'getOuterHtml',
'getInnerHtml', 'getId', 'getRawId', 'serialize', 'takeScreenshot'
];

@@ -237,3 +236,3 @@ // Explicitly define webdriver.WebElement.

* Get an element within the ElementArrayFinder by index. The index starts at
* 0. Negative indices are wrapped (i.e. -i means ith element from last)
* 0\. Negative indices are wrapped (i.e. -i means ith element from last)
* This does not actually retrieve the underlying element.

@@ -260,4 +259,3 @@ *

var getWebElements = function () {
return webdriver.promise.all([index, _this.getWebElements()])
.then(function (results) {
return webdriver.promise.all([index, _this.getWebElements()]).then(function (results) {
var i = results[0];

@@ -271,4 +269,3 @@ var parentWebElements = results[1];

throw new selenium_webdriver_1.error.NoSuchElementError('Index out of bound. ' +
'Trying to access element at index: ' + index +
', but there are ' +
'Trying to access element at index: ' + index + ', but there are ' +
'only ' + parentWebElements.length + ' elements that match ' +

@@ -280,4 +277,3 @@ 'locator ' + _this.locator_.toString());

};
return new ElementArrayFinder(this.browser_, getWebElements, this.locator_)
.toElementFinder_();
return new ElementArrayFinder(this.browser_, getWebElements, this.locator_).toElementFinder_();
};

@@ -368,4 +364,3 @@ /**

}, function (err) {
if (err.code &&
err.code == new webdriver.error.NoSuchElementError()) {
if (err.code && err.code == new webdriver.error.NoSuchElementError()) {
return 0;

@@ -406,17 +401,12 @@ }

*/
// map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?:
// any): U[];
// map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
ElementArrayFinder.prototype.applyAction_ = function (actionFn) {
var callerError = new Error();
var actionResults = this.getWebElements()
.then(function (arr) {
return webdriver.promise.all(arr.map(actionFn));
})
.then(function (arr) { return webdriver.promise.all(arr.map(actionFn)); })
.then(null, function (e) {
var noSuchErr;
var stack;
if (e instanceof Error) {
noSuchErr = e;
noSuchErr.stack = noSuchErr.stack +
callerError.stack;
noSuchErr.stack = noSuchErr.stack + callerError.stack;
}

@@ -724,4 +714,3 @@ else {

if (webElements.length === 0) {
throw new selenium_webdriver_1.error.NoSuchElementError('No element found using locator: ' +
elementArrayFinder.locator().toString());
throw new selenium_webdriver_1.error.NoSuchElementError('No element found using locator: ' + elementArrayFinder.locator().toString());
}

@@ -731,4 +720,3 @@ else {

logger.warn('more than one element found for locator ' +
elementArrayFinder.locator().toString() +
' - the first result will be used');
elementArrayFinder.locator().toString() + ' - the first result will be used');
}

@@ -758,4 +746,3 @@ return [webElements[0]];

};
return new ElementArrayFinder(browser, getWebElements, locator)
.toElementFinder_();
return new ElementArrayFinder(browser, getWebElements, locator).toElementFinder_();
};

@@ -934,4 +921,3 @@ /**

}, function (err) {
if (err.code ==
webdriver.error.ErrorCode.STALE_ELEMENT_REFERENCE) {
if (err.code == webdriver.error.ErrorCode.STALE_ELEMENT_REFERENCE) {
return false;

@@ -938,0 +924,0 @@ }

@@ -90,2 +90,12 @@ var q = require('q');

// Run specs in semi-random order
if (jasmineNodeOpts.random) {
jasmine.getEnv().randomizeTests(true);
// Sets the randomization seed if randomization is turned on
if (jasmineNodeOpts.seed) {
jasmine.getEnv().seed(jasmineNodeOpts.seed);
}
}
return runner.runTestPreparer().then(function() {

@@ -92,0 +102,0 @@ return q.promise(function(resolve, reject) {

@@ -42,13 +42,12 @@ "use strict";

exports.CommandName = require('selenium-webdriver/lib/command').Name;
// Export API instances based on the global Protractor object.
// We base this on NodeJS `global` because we do not want to mask
// with a different instance of Protractor if the module is
// installed both globally and locally.
exports.protractor = global['protractor'];
exports.browser = exports.protractor ? exports.protractor.browser : undefined;
exports.$ = exports.protractor ? exports.protractor.$ : undefined;
exports.$$ = exports.protractor ? exports.protractor.$$ : undefined;
exports.element = exports.protractor ? exports.protractor.element : undefined;
exports.By = exports.protractor ? exports.protractor.By : undefined;
exports.by = exports.protractor ? exports.protractor.by : undefined;
exports.ExpectedConditions = exports.protractor ? exports.protractor.ExpectedConditions : undefined;
Object.defineProperty(exports, 'protractor', { get: function () { return global['protractor']; } });
function registerGlobal(name) {
Object.defineProperty(exports, name, { get: function () { return exports.protractor ? exports.protractor[name] : undefined; } });
}
registerGlobal('browser');
registerGlobal('$');
registerGlobal('$$');
registerGlobal('element');
registerGlobal('By');
registerGlobal('by');
registerGlobal('ExpectedConditions');

@@ -36,5 +36,3 @@ "use strict";

return this.results_.reduce(function (processFailures, result) {
return !result.failedCount && result.exitCode !== 0 ?
processFailures + 1 :
processFailures;
return !result.failedCount && result.exitCode !== 0 ? processFailures + 1 : processFailures;
}, 0);

@@ -60,5 +58,3 @@ };

shortName += (capabilities.version) ? capabilities.version : '';
shortName += (capabilities.logName && capabilities.count < 2) ?
'' :
' #' + result.taskId;
shortName += (capabilities.logName && capabilities.count < 2) ? '' : ' #' + result.taskId;
if (result.failedCount) {

@@ -75,4 +71,4 @@ logger.info(shortName + ' failed ' + result.failedCount + ' test(s)');

if (specFailures && processFailures) {
logger.info('overall: ' + specFailures + ' failed spec(s) and ' +
processFailures + ' process(es) failed to complete');
logger.info('overall: ' + specFailures + ' failed spec(s) and ' + processFailures +
' process(es) failed to complete');
}

@@ -209,4 +205,3 @@ else if (specFailures) {

var cleanUpAndExit = function (exitCode) {
return helper
.runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode])
return helper.runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode])
.then(function (returned) {

@@ -226,4 +221,3 @@ if (typeof returned === 'number') {

var forkProcess = false;
if (totalTasks >
1) {
if (totalTasks > 1) {
forkProcess = true;

@@ -242,4 +236,3 @@ if (config.debug) {

if (result.exitCode && !result.failedCount) {
logger.error('Runner process exited unexpectedly with error code: ' +
result.exitCode);
logger.error('Runner process exited unexpectedly with error code: ' + result.exitCode);
}

@@ -253,4 +246,3 @@ taskResults_.add(result);

}
logger.info(scheduler.countActiveTasks() +
' instance(s) of WebDriver still running');
logger.info(scheduler.countActiveTasks() + ' instance(s) of WebDriver still running');
})

@@ -270,4 +262,3 @@ .catch(function (err) {

}
logger.info('Running ' + scheduler.countActiveTasks() +
' instances of WebDriver');
logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver');
// By now all runners have completed.

@@ -274,0 +265,0 @@ deferred.promise

@@ -89,4 +89,3 @@ "use strict";

toString: function () {
return 'by.' + name + '("' +
Array.prototype.join.call(locatorArguments, '", "') + '")';
return 'by.' + name + '("' + Array.prototype.join.call(locatorArguments, '", "') + '")';
}

@@ -264,4 +263,4 @@ };

toString: function () {
return name + '("' + repeatDescriptor + '").row("' + index +
'").column("' + binding + '")';
return name + '("' + repeatDescriptor + '").row("' + index + '").column("' +
binding + '")';
}

@@ -278,4 +277,3 @@ };

toString: function () {
return name + '("' + repeatDescriptor + '").column("' + binding +
'")';
return name + '("' + repeatDescriptor + '").column("' + binding + '")';
},

@@ -288,4 +286,4 @@ row: function (index) {

toString: function () {
return name + '("' + repeatDescriptor + '").column("' +
binding + '").row("' + index + '")';
return name + '("' + repeatDescriptor + '").column("' + binding + '").row("' +
index + '")';
}

@@ -399,4 +397,3 @@ };

toString: function () {
return 'by.cssContainingText("' + cssSelector + '", "' + searchText +
'")';
return 'by.cssContainingText("' + cssSelector + '", "' + searchText + '")';
}

@@ -403,0 +400,0 @@ };

@@ -223,3 +223,2 @@ "use strict";

Logger.id_ = function (logLevel, id, writeTo) {
var level = LogLevel[logLevel].toString();
if (writeTo === WriteTo.FILE) {

@@ -226,0 +225,0 @@ return '/' + id;

/// <reference types="q" />
import * as Q from 'q';
/// <reference types="selenium-webdriver" />
import * as q from 'q';
import * as webdriver from 'selenium-webdriver';
import { Config } from './config';
export declare enum PromiseType {

@@ -28,3 +31,3 @@ Q = 0,

*/
setup?: () => Q.Promise<any>;
setup?: () => q.Promise<any>;
/**

@@ -44,3 +47,3 @@ * This is called before the test have been run but after the test framework has

*/
onPrepare?: () => Q.Promise<any>;
onPrepare?: () => q.Promise<any>;
/**

@@ -59,3 +62,3 @@ * This is called after the tests have been run, but before the WebDriver

*/
teardown?: () => Q.Promise<any>;
teardown?: () => q.Promise<any>;
/**

@@ -73,3 +76,3 @@ * Called after the test results have been finalized and any jobs have been

*/
postResults?: () => Q.Promise<any>;
postResults?: () => q.Promise<any>;
/**

@@ -92,3 +95,3 @@ * Called after each test block (in Jasmine, this means an `it` block)

*/
postTest?: (passed: boolean, testInfo: any) => Q.Promise<any>;
postTest?: (passed: boolean, testInfo: any) => q.Promise<any>;
/**

@@ -107,3 +110,3 @@ * This is called inside browser.get() directly after the page loads, and before

*/
onPageLoad?: () => Q.Promise<any>;
onPageLoad?: () => q.Promise<any>;
/**

@@ -123,3 +126,3 @@ * This is called inside browser.get() directly after angular is done

*/
onPageStable?: () => Q.Promise<any>;
onPageStable?: () => q.Promise<any>;
/**

@@ -143,3 +146,3 @@ * Between every webdriver action, Protractor calls browser.waitForAngular() to

*/
waitForPromise?: () => Q.Promise<any>;
waitForPromise?: () => q.Promise<any>;
/**

@@ -162,3 +165,3 @@ * Between every webdriver action, Protractor calls browser.waitForAngular() to

*/
waitForCondition?: () => Q.Promise<any>;
waitForCondition?: () => q.Promise<any>;
/**

@@ -255,6 +258,6 @@ * Used to turn off default checks for angular stability

assertions: {
[key: string]: any[];
[key: string]: AssertionResult[];
};
resultsReported: boolean;
constructor(config: any);
constructor(config: Config);
/**

@@ -277,3 +280,3 @@ * Adds properties to a plugin's object

failedCount: number;
specResults: any[];
specResults: SpecResult[];
};

@@ -289,11 +292,11 @@ /**

*/
setup: Function;
onPrepare: Function;
teardown: Function;
postResults: Function;
postTest: Function;
onPageLoad: Function;
onPageStable: Function;
waitForPromise: Function;
waitForCondition: Function;
setup: (...args: any[]) => q.Promise<any[]>;
onPrepare: (...args: any[]) => q.Promise<any[]>;
teardown: (...args: any[]) => q.Promise<any[]>;
postResults: (...args: any[]) => q.Promise<any[]>;
postTest: (...args: any[]) => q.Promise<any[]>;
onPageLoad: (...args: any[]) => webdriver.promise.Promise<any[]>;
onPageStable: (...args: any[]) => webdriver.promise.Promise<any[]>;
waitForPromise: (...args: any[]) => webdriver.promise.Promise<any[]>;
waitForCondition: (...args: any[]) => webdriver.promise.Promise<any[]>;
/**

@@ -316,3 +319,23 @@ * Calls a function from a plugin safely. If the plugin's function throws an

*/
safeCallPluginFun(pluginObj: ProtractorPlugin, funName: string, args: IArguments, promiseType: PromiseType, failReturnVal: any): any;
private safeCallPluginFun(pluginObj, funName, args, promiseType, failReturnVal);
/**
* Generates the handler for a plugin function (e.g. the setup() function)
*
* @param {string} funName The name of the function to make a handler for
* @param {PromiseType} promiseType The type of promise (WebDriver or Q) that should be used
* @param {boolean=} failReturnVal The value that the function should return if the plugin crashes
*
* @return The handler
*/
private pluginFunFactory(funName, promiseType, failReturnVal?);
private pluginFunFactory(funName, promiseType, failReturnVal?);
}
export interface SpecResult {
description: string;
assertions: AssertionResult[];
}
export interface AssertionResult {
passed: boolean;
errorMsg?: string;
stackTrace?: string;
}
"use strict";
var q = require('q');
var webdriver = require('selenium-webdriver');
var configParser_1 = require('./configParser');
var logger_1 = require('./logger');
var Q = require('q');
var configParser_1 = require('./configParser');
var logger = new logger_1.Logger('plugins');

@@ -25,41 +25,42 @@ (function (PromiseType) {

*/
this.setup = pluginFunFactory('setup', PromiseType.Q);
this.onPrepare = pluginFunFactory('onPrepare', PromiseType.Q);
this.teardown = pluginFunFactory('teardown', PromiseType.Q);
this.postResults = pluginFunFactory('postResults', PromiseType.Q);
this.postTest = pluginFunFactory('postTest', PromiseType.Q);
this.onPageLoad = pluginFunFactory('onPageLoad', PromiseType.WEBDRIVER);
this.onPageStable = pluginFunFactory('onPageStable', PromiseType.WEBDRIVER);
this.waitForPromise = pluginFunFactory('waitForPromise', PromiseType.WEBDRIVER);
this.waitForCondition = pluginFunFactory('waitForCondition', PromiseType.WEBDRIVER, true);
this.setup = this.pluginFunFactory('setup', PromiseType.Q);
this.onPrepare = this.pluginFunFactory('onPrepare', PromiseType.Q);
this.teardown = this.pluginFunFactory('teardown', PromiseType.Q);
this.postResults = this.pluginFunFactory('postResults', PromiseType.Q);
this.postTest = this.pluginFunFactory('postTest', PromiseType.Q);
this.onPageLoad = this.pluginFunFactory('onPageLoad', PromiseType.WEBDRIVER);
this.onPageStable = this.pluginFunFactory('onPageStable', PromiseType.WEBDRIVER);
this.waitForPromise = this.pluginFunFactory('waitForPromise', PromiseType.WEBDRIVER);
this.waitForCondition = this.pluginFunFactory('waitForCondition', PromiseType.WEBDRIVER, true);
this.pluginObjs = [];
this.assertions = {};
this.resultsReported = false;
var pluginConfs = config.plugins || [];
pluginConfs.forEach(function (pluginConf, i) {
var path;
if (pluginConf.path) {
path = configParser_1.ConfigParser.resolveFilePatterns(pluginConf.path, true, config.configDir)[0];
if (!path) {
throw new Error('Invalid path to plugin: ' + pluginConf.path);
if (config.plugins) {
config.plugins.forEach(function (pluginConf, i) {
var path;
if (pluginConf.path) {
path = configParser_1.ConfigParser.resolveFilePatterns(pluginConf.path, true, config.configDir)[0];
if (!path) {
throw new Error('Invalid path to plugin: ' + pluginConf.path);
}
}
}
else {
path = pluginConf.package;
}
var pluginObj;
if (path) {
pluginObj = require(path);
}
else if (pluginConf.inline) {
pluginObj = pluginConf.inline;
}
else {
throw new Error('Plugin configuration did not contain a valid path or ' +
'inline definition.');
}
_this.annotatePluginObj(pluginObj, pluginConf, i);
logger.debug('Plugin "' + pluginObj.name + '" loaded.');
_this.pluginObjs.push(pluginObj);
});
else {
path = pluginConf.package;
}
var pluginObj;
if (path) {
pluginObj = require(path);
}
else if (pluginConf.inline) {
pluginObj = pluginConf.inline;
}
else {
throw new Error('Plugin configuration did not contain a valid path or ' +
'inline definition.');
}
_this.annotatePluginObj(pluginObj, pluginConf, i);
logger.debug('Plugin "' + pluginObj.name + '" loaded.');
_this.pluginObjs.push(pluginObj);
});
}
}

@@ -91,4 +92,3 @@ ;

};
obj.name =
obj.name || conf.name || conf.path || conf.package || ('Plugin #' + i);
obj.name = obj.name || conf.name || conf.path || conf.package || ('Plugin #' + i);
obj.config = conf;

@@ -103,5 +103,5 @@ obj.addFailure = function (message, info) {

options = options || {};
logger.warn('Warning ' + (options.specName ? 'in ' + options.specName :
'from "' + obj.name + '" plugin') +
': ' + message);
logger.warn('Warning ' +
(options.specName ? 'in ' + options.specName : 'from "' + obj.name + '" plugin') + ': ' +
message);
};

@@ -116,15 +116,9 @@ };

};
for (var j = 0; j < specResults.length; j++) {
var specResult = specResults[j];
var passed = specResult.assertions
.map(function (x) {
return x.passed;
})
.reduce(function (x, y) {
return x && y;
}, true);
for (var _i = 0, specResults_1 = specResults; _i < specResults_1.length; _i++) {
var specResult = specResults_1[_i];
var passed = specResult.assertions.map(function (x) { return x.passed; }).reduce(function (x, y) { return (x && y); }, true);
printResult(specResult.description, passed);
if (!passed) {
for (var k = 0; k < specResult.assertions.length; k++) {
var assertion = specResult.assertions[k];
for (var _a = 0, _b = specResult.assertions; _a < _b.length; _a++) {
var assertion = _b[_a];
if (!assertion.passed) {

@@ -152,7 +146,4 @@ logger.error('\t\t' + assertion.errorMsg);

results.specResults.push({ description: specName, assertions: this.assertions[specName] });
results.failedCount += this.assertions[specName]
.filter(function (assertion) {
return !assertion.passed;
})
.length;
results.failedCount +=
this.assertions[specName].filter(function (assertion) { return !assertion.passed; }).length;
}

@@ -170,5 +161,3 @@ this.printPluginResults(results.specResults);

Plugins.prototype.skipAngularStability = function () {
var result = this.pluginObjs.some(function (pluginObj) {
return pluginObj.skipAngularStability;
});
var result = this.pluginObjs.some(function (pluginObj) { return pluginObj.skipAngularStability; });
return result;

@@ -196,36 +185,48 @@ };

var _this = this;
var deferred = promiseType == PromiseType.Q ? Q.defer() : webdriver.promise.defer();
var logError = function (e) {
if (_this.resultsReported) {
_this.printPluginResults([{
description: pluginObj.name + ' Runtime',
assertions: [{
passed: false,
errorMsg: 'Failure during ' + funName + ': ' + (e.message || e),
stackTrace: e.stack
}]
}]);
var resolver = function (done) {
var logError = function (e) {
if (_this.resultsReported) {
_this.printPluginResults([{
description: pluginObj.name + ' Runtime',
assertions: [{
passed: false,
errorMsg: 'Failure during ' + funName + ': ' + (e.message || e),
stackTrace: e.stack
}]
}]);
}
else {
pluginObj.addFailure('Failure during ' + funName + ': ' + e.message || e, { stackTrace: e.stack });
}
done(failReturnVal);
};
try {
var result = pluginObj[funName].apply(pluginObj, args);
if (webdriver.promise.isPromise(result)) {
result.then(done, logError);
}
else {
done(result);
}
}
else {
pluginObj.addFailure('Failure during ' + funName + ': ' + e.message || e, { stackTrace: e.stack });
catch (e) {
logError(e);
}
deferred.fulfill(failReturnVal);
};
try {
var result = pluginObj[funName].apply(pluginObj, args);
if (webdriver.promise.isPromise(result)) {
result.then(function () {
deferred.fulfill.apply(deferred, arguments);
}, function (e) {
logError(e);
});
return promiseType == PromiseType.Q ? q.Promise(resolver) :
new webdriver.promise.Promise(resolver);
};
Plugins.prototype.pluginFunFactory = function (funName, promiseType, failReturnVal) {
var _this = this;
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i - 0] = arguments[_i];
}
else {
deferred.fulfill(result);
}
}
catch (e) {
logError(e);
}
return deferred.promise;
var promises = _this.pluginObjs.filter(function (pluginObj) { return typeof pluginObj[funName] === 'function'; })
.map(function (pluginObj) {
return _this.safeCallPluginFun(pluginObj, funName, args, promiseType, failReturnVal);
});
return promiseType == PromiseType.Q ? q.all(promises) : webdriver.promise.all(promises);
};
};

@@ -235,30 +236,1 @@ return Plugins;

exports.Plugins = Plugins;
/**
* Generates the handler for a plugin function (e.g. the setup() function)
*
* @param {string} funName The name of the function to make a handler for
* @param {PromiseType} promiseType The type of promise (WebDriver or Q) that
* should be used
* @param {boolean=} failReturnVal The value that the function should return if
* the plugin crashes
*
* @return {Function} The handler
*/
function pluginFunFactory(funName, promiseType, failReturnVal) {
return function () {
var promises = [];
var args = arguments;
var self = this;
self.pluginObjs.forEach(function (pluginObj) {
if (pluginObj[funName]) {
promises.push(self.safeCallPluginFun(pluginObj, funName, args, promiseType, failReturnVal));
}
});
if (promiseType == PromiseType.Q) {
return Q.all(promises);
}
else {
return webdriver.promise.all(promises);
}
};
}

@@ -40,4 +40,3 @@ "use strict";

this.exit_ = function (exitCode) {
return helper
.runFilenameOrFn_(this.config_.configDir, this.config_.onCleanUp, [exitCode])
return helper.runFilenameOrFn_(this.config_.configDir, this.config_.onCleanUp, [exitCode])
.then(function (returned) {

@@ -220,20 +219,18 @@ if (typeof returned === 'number') {

}
browser_.ready =
driver.manage().timeouts().setScriptTimeout(config.allScriptsTimeout);
browser_.ready = driver.manage().timeouts().setScriptTimeout(config.allScriptsTimeout);
browser_.getProcessedConfig = function () {
return webdriver.promise.fulfilled(config);
};
browser_.forkNewDriverInstance =
function (opt_useSameUrl, opt_copyMockModules) {
var newBrowser = _this.createBrowser(plugins);
if (opt_copyMockModules) {
newBrowser.mockModules_ = browser_.mockModules_;
}
if (opt_useSameUrl) {
browser_.driver.getCurrentUrl().then(function (url) {
newBrowser.get(url);
});
}
return newBrowser;
};
browser_.forkNewDriverInstance = function (opt_useSameUrl, opt_copyMockModules) {
var newBrowser = _this.createBrowser(plugins);
if (opt_copyMockModules) {
newBrowser.mockModules_ = browser_.mockModules_;
}
if (opt_useSameUrl) {
browser_.driver.getCurrentUrl().then(function (url) {
newBrowser.get(url);
});
}
return newBrowser;
};
browser_.restart = function () {

@@ -243,9 +240,3 @@ // Note: because tests are not paused at this point, any async

_this.driverprovider_.quitDriver(browser_.driver);
// Copy mock modules, but do not navigate to previous URL.
var forkBrowser = browser_.forkNewDriverInstance(false, true);
// Replace the items in browser_ but do not create a new object
// since this will break typescript imports
for (var item in forkBrowser) {
browser_[item] = forkBrowser[item];
}
browser_ = browser_.forkNewDriverInstance(false, true);
_this.setupGlobals_(browser_);

@@ -308,4 +299,3 @@ };

var frameworkPath = '';
if (_this.config_.framework === 'jasmine' ||
_this.config_.framework === 'jasmine2') {
if (_this.config_.framework === 'jasmine' || _this.config_.framework === 'jasmine2') {
frameworkPath = './frameworks/jasmine.js';

@@ -332,4 +322,3 @@ }

else {
throw new Error('config.framework (' + _this.config_.framework +
') is not a valid framework.');
throw new Error('config.framework (' + _this.config_.framework + ') is not a valid framework.');
}

@@ -372,4 +361,3 @@ if (_this.config_.restartBrowserBetweenTests) {

if (_this.driverprovider_.updateJob) {
return _this.driverprovider_.updateJob({ 'passed': testPassed })
.then(function () {
return _this.driverprovider_.updateJob({ 'passed': testPassed }).then(function () {
return _this.driverprovider_.teardownEnv();

@@ -376,0 +364,0 @@ });

@@ -63,10 +63,7 @@ "use strict";

var capabilities = this.task.capabilities;
tag += (capabilities.logName) ?
capabilities.logName :
tag += (capabilities.logName) ? capabilities.logName :
(capabilities.browserName) ? capabilities.browserName : '';
tag += (capabilities.version) ? (' ' + capabilities.version) : '';
tag += (capabilities.platform) ? (' ' + capabilities.platform) : '';
tag += (capabilities.logName && capabilities.count < 2) ?
'' :
' #' + this.task.taskId;
tag += (capabilities.logName && capabilities.count < 2) ? '' : ' #' + this.task.taskId;
tag += '] ';

@@ -73,0 +70,0 @@ data = data.toString();

@@ -34,4 +34,3 @@ "use strict";

var excludes = configParser_1.ConfigParser.resolveFilePatterns(config.exclude, true, config.configDir);
var allSpecs = configParser_1.ConfigParser
.resolveFilePatterns(configParser_1.ConfigParser.getSpecs(config), false, config.configDir)
var allSpecs = configParser_1.ConfigParser.resolveFilePatterns(configParser_1.ConfigParser.getSpecs(config), false, config.configDir)
.filter(function (path) {

@@ -113,4 +112,3 @@ return excludes.indexOf(path) < 0;

this.taskQueues.forEach(function (queue) {
count += queue.numRunningInstances +
(queue.specLists.length - queue.specsIndex);
count += queue.numRunningInstances + (queue.specLists.length - queue.specsIndex);
});

@@ -117,0 +115,0 @@ return count;

@@ -5,5 +5,4 @@ "use strict";

var STACK_SUBSTRINGS_TO_FILTER = [
'node_modules/jasmine/', 'node_modules/selenium-webdriver', 'at Module.',
'at Object.Module.', 'at Function.Module', '(timers.js:',
'jasminewd2/index.js', 'protractor/lib/'
'node_modules/jasmine/', 'node_modules/selenium-webdriver', 'at Module.', 'at Object.Module.',
'at Function.Module', '(timers.js:', 'jasminewd2/index.js', 'protractor/lib/'
];

@@ -40,5 +39,3 @@ /**

return q_1.Promise(function (resolvePromise) {
if (filenameOrFn &&
!(typeof filenameOrFn === 'string' ||
typeof filenameOrFn === 'function')) {
if (filenameOrFn && !(typeof filenameOrFn === 'string' || typeof filenameOrFn === 'function')) {
throw new Error('filenameOrFn must be a string or function');

@@ -56,3 +53,3 @@ }

err = err;
if (err.stack) {
if (!err.stack) {
err.stack = new Error().stack;

@@ -59,0 +56,0 @@ }

@@ -1,8 +0,29 @@

`async`/`await` in Protractor
=============================
`async`/`await` and the Web Driver Control Flow
===============================================
`async`/`await` is a feature that may or may not be added to javascript in
the future. It is currently accessible via typescript if you compile using
`tsc -t ES2015 <files>`. Protractor supports returning a promise at the end of
an `it()` block, so it indirectly supports `async`/`await` (so long as your
programming environment supports it).
The Web Driver Control Flow is used to synchronize your commands so they reach
the browser in the correct order (see [control-flow.md](
../../docs/control-flow.md) for details). In the future, the control flow is
being removed, however (see [github issue](
https://github.com/SeleniumHQ/selenium/issues/2969) for details). Instead of
the control flow, you can synchronize your commands with promise chaining or the
upcomming ES7 feature `async`/`await`. However, you cannot use a mix of
`async`/`await` and the control flow: `async`/`await` causes the control flow to
become unreliable (see [github issue](
https://github.com/SeleniumHQ/selenium/issues/3037)). So if you `async`/`await`
anywhere in a spec, you should use `await` or promise chaining to handle all
asynchronous activity (e.g. any command interacting with the browser) for the
rest of that test.
In the near future there will be an option to disable the Web Driver control
flow entierly (see https://github.com/angular/protractor/issues/3691). If you
are using `async`/`await`, it is highly recommended that you disable the Web
Driver control flow.
Compiling `async`/`await` syntax
================================
`async`/`await` syntax is currently accessible via typescript if you compile
using `tsc -t ES2015 <files>`. You can also compile it using [regenerator](
https://github.com/facebook/regenerator).

@@ -1,3 +0,2 @@

// Same process for importing and compiling at ../spec.ts, except you need to
// pass the `-t ES2015` flag to `tsc`.
// See README.md for important details.
import {browser, element, by, By, $, $$, ExpectedConditions} from 'protractor';

@@ -4,0 +3,0 @@

@@ -87,3 +87,3 @@ 'use strict';

gulp.task('prepublish', function(done) {
runSequence('checkVersion', ['jshint', 'format'], 'tsc',
runSequence('checkVersion', 'jshint', 'tsc',
'built:copy', done);

@@ -90,0 +90,0 @@ });

@@ -22,3 +22,3 @@ {

"glob": "^7.0.3",
"jasmine": "2.5.2",
"jasmine": "2.4.1",
"jasminewd2": "0.0.10",

@@ -30,3 +30,3 @@ "optimist": "~0.6.0",

"source-map-support": "~0.4.0",
"webdriver-manager": "^10.2.6"
"webdriver-manager": "^10.2.8"
},

@@ -79,3 +79,3 @@ "devDependencies": {

},
"version": "4.0.10"
"version": "4.0.11"
}

@@ -1,2 +0,2 @@

Protractor [![Build Status](https://travis-ci.org/angular/protractor.png?branch=master)](https://travis-ci.org/angular/protractor) [![Join the chat at https://gitter.im/angular/protractor](https://badges.gitter.im/angular/protractor.svg)](https://gitter.im/angular/protractor)
Protractor [![Build Status](https://travis-ci.org/angular/protractor.svg?branch=master)](https://travis-ci.org/angular/protractor) [![CircleCI Status](https://circleci.com/gh/angular/protractor.svg?style=shield)](https://circleci.com/gh/angular/protractor) [![Join the chat at https://gitter.im/angular/protractor](https://badges.gitter.im/angular/protractor.svg)](https://gitter.im/angular/protractor)
==========

@@ -9,5 +9,5 @@

Protractor 4 is compatible with nodejs v4 and newer. If you absolutely need to use nodjs at 0.12, use Protractor@2.
Protractor 4 is compatible with nodejs v4 and newer. If you absolutely need to use nodejs at 0.12, use Protractor@2.
Protractor work with Angular versions greater than 1.0.6/1.1.4, and is compatible with Angular 2 applications. Note that for Angular 2 apps, the `binding` and `model` locators are not supported. We recommend using `by.css`.
Protractor works with Angular versions greater than 1.0.6/1.1.4, and is compatible with Angular 2 applications. Note that for Angular 2 apps, the `binding` and `model` locators are not supported. We recommend using `by.css`.

@@ -14,0 +14,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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