aboutsummaryrefslogtreecommitdiff
path: root/node_modules/selenium-webdriver
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-04-20 03:09:25 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-04-24 16:14:29 +0200
commit82f2b76e25a4a67e01ec67e5ebe39d14ad771ea8 (patch)
tree965f6eb89b84d65a62b49008fd972c004832ccd1 /node_modules/selenium-webdriver
parente6e0cbc387c2a77b48e4065c229daa65bf1aa0fa (diff)
Reorganize module loading.
We now use webpack instead of SystemJS, effectively bundling modules into one file (plus commons chunks) for every entry point. This results in a much smaller extension size (almost half). Furthermore we use yarn/npm even for extension run-time dependencies. This relieves us from manually vendoring and building dependencies. It's also easier to understand for new developers familiar with node.
Diffstat (limited to 'node_modules/selenium-webdriver')
-rw-r--r--node_modules/selenium-webdriver/CHANGES.md39
-rw-r--r--node_modules/selenium-webdriver/README.md18
-rw-r--r--node_modules/selenium-webdriver/chrome.js6
-rw-r--r--node_modules/selenium-webdriver/edge.js2
-rw-r--r--node_modules/selenium-webdriver/firefox/binary.js171
-rw-r--r--node_modules/selenium-webdriver/firefox/extension.js2
-rw-r--r--node_modules/selenium-webdriver/firefox/index.js88
-rw-r--r--node_modules/selenium-webdriver/index.js4
-rw-r--r--node_modules/selenium-webdriver/lib/README5
-rw-r--r--node_modules/selenium-webdriver/lib/actions.js8
-rw-r--r--node_modules/selenium-webdriver/lib/by.js2
-rw-r--r--node_modules/selenium-webdriver/lib/capabilities.js8
-rw-r--r--node_modules/selenium-webdriver/lib/error.js19
-rw-r--r--node_modules/selenium-webdriver/lib/events.js2
-rw-r--r--node_modules/selenium-webdriver/lib/firefox/amd64/libnoblur64.sobin41623 -> 0 bytes
-rw-r--r--node_modules/selenium-webdriver/lib/firefox/i386/libnoblur.sobin36934 -> 0 bytes
-rw-r--r--node_modules/selenium-webdriver/lib/firefox/webdriver.json3
-rw-r--r--node_modules/selenium-webdriver/lib/firefox/webdriver.xpibin707042 -> 703396 bytes
-rw-r--r--node_modules/selenium-webdriver/lib/http.js102
-rw-r--r--node_modules/selenium-webdriver/lib/input.js2
-rw-r--r--node_modules/selenium-webdriver/lib/promise.js286
-rw-r--r--node_modules/selenium-webdriver/lib/symbols.js2
-rw-r--r--node_modules/selenium-webdriver/lib/test/index.js6
-rw-r--r--node_modules/selenium-webdriver/lib/until.js2
-rw-r--r--node_modules/selenium-webdriver/lib/webdriver.js24
-rw-r--r--node_modules/selenium-webdriver/opera.js2
-rw-r--r--node_modules/selenium-webdriver/package.json2
-rw-r--r--node_modules/selenium-webdriver/remote/index.js7
-rw-r--r--node_modules/selenium-webdriver/safari.js51
-rw-r--r--node_modules/selenium-webdriver/test/firefox/firefox_test.js40
-rw-r--r--node_modules/selenium-webdriver/test/lib/http_test.js31
-rw-r--r--node_modules/selenium-webdriver/test/lib/promise_test.js19
-rw-r--r--node_modules/selenium-webdriver/test/lib/until_test.js41
-rw-r--r--node_modules/selenium-webdriver/testing/index.js21
34 files changed, 710 insertions, 305 deletions
diff --git a/node_modules/selenium-webdriver/CHANGES.md b/node_modules/selenium-webdriver/CHANGES.md
index b9ac5fd22..1cdc96814 100644
--- a/node_modules/selenium-webdriver/CHANGES.md
+++ b/node_modules/selenium-webdriver/CHANGES.md
@@ -1,3 +1,42 @@
+## v3.3.0
+
+* Added warning log messages when the user creates new managed promises, or
+ schedules unchained tasks. Users may opt in to printing these log messages
+ with
+
+ ```js
+ const {logging} = require('selenium-webdriver');
+ logging.installConsoleHandler();
+ logging.getLogger('promise.ControlFlow').setLevel(logging.Level.WARNING);
+ ```
+* If the `JAVA_HOME` environment variable is set, use it to locate java.exe.
+
+
+## v3.2.0
+
+* Release skipped to stay in sync with the main Selenium project.
+
+
+## v3.1.0
+
+* The `lib` package is once again platform agnostic (excluding `lib/devmode`).
+* Deprecated `promise.when(value, callback, errback)`.
+ Use `promise.fulfilled(value).then(callback, errback)`
+* Changed `promise.fulfilled(value)`, `promise.rejected(reason)` and
+ `promise.defer()` to all use native promises when the promise manager is
+ disabled.
+* Properly handle W3C error responses to new session commands.
+* Updated `selenium-webdriver/testing` to export `describe.only` along with
+ `describe.skip`.
+* Fixed `selenium-webdriver/lib/until.ableToSwitchToFrame`. It was previously
+ dropping arguments and would never work.
+* Added the ability to use Firefox Nightly
+* If Firefox cannot be found in the default location, look for it on the PATH
+* Allow SafariDriver to use Safari Technology Preview.
+* Use the proper wire command for WebElement.getLocation() and
+ WebElement.getSize() for W3C compliant drivers.
+
+
## v3.0.1
* More API adjustments to align with native Promises
diff --git a/node_modules/selenium-webdriver/README.md b/node_modules/selenium-webdriver/README.md
index bc281d504..31708b186 100644
--- a/node_modules/selenium-webdriver/README.md
+++ b/node_modules/selenium-webdriver/README.md
@@ -136,16 +136,16 @@ will also have "best effort" support. Releases older than the latest LTS,
_semver-major_ releases, and all unstable release branches (e.g. "v.Next")
are considered strictly unsupported.
-For example, suppose the current LTS and stable releases are v4.2.4 and v5.4.1,
+For example, suppose the current LTS and stable releases are v6.9.5 and v7.5.0,
respectively. Then a Selenium release would have the following support levels:
| Version | Support |
| ------- | ------------- |
-| <= 4.1 | _unsupported_ |
-| 4.2 | supported |
-| 5.0-3 | best effort |
-| 5.4 | supported |
-| >= 5.5 | best effort |
+| <= 6.8 | _unsupported_ |
+| 6.9 | supported |
+| 7.0-4 | best effort |
+| 7.5 | supported |
+| >= 7.5 | best effort |
| v.Next | _unsupported_ |
### Support Level Definitions
@@ -168,11 +168,11 @@ months, the support window for selenium-webdriver will be roughly:
| Date | LTS | Stable |
| --------- | ---: | -----: |
-| (current) | 4.2 | 5.0 |
-| 2016-04 | 4.2 | 6.0 |
-| 2016-10 | 6.0 | 7.0 |
+| (current) | 6.9 | 7.5 |
| 2017-04 | 6.0 | 8.0 |
| 2017-10 | 8.0 | 9.0 |
+| 2018-04 | 8.0 | 10.0 |
+| 2018-10 | 10.0 | 11.0 |
## Issues
diff --git a/node_modules/selenium-webdriver/chrome.js b/node_modules/selenium-webdriver/chrome.js
index eb33df9ed..2dbc93351 100644
--- a/node_modules/selenium-webdriver/chrome.js
+++ b/node_modules/selenium-webdriver/chrome.js
@@ -59,7 +59,7 @@
* let options = new chrome.Options();
* // configure browser options ...
*
- * let driver = new chrome.Driver(options, service);
+ * let driver = chrome.Driver.createSession(options, service);
*
* Users should only instantiate the {@link Driver} class directly when they
* need a custom driver service configuration (as shown above). For normal
@@ -595,7 +595,7 @@ class Options {
* let options = new chrome.Options().setMobileEmulation(
* {deviceName: 'Google Nexus 5'});
*
- * let driver = new chrome.Driver(options);
+ * let driver = chrome.Driver.createSession(options);
*
* __Example 2: Using Custom Screen Configuration__
*
@@ -605,7 +605,7 @@ class Options {
* pixelRatio: 3.0
* });
*
- * let driver = new chrome.Driver(options);
+ * let driver = chrome.Driver.createSession(options);
*
*
* [em]: https://sites.google.com/a/chromium.org/chromedriver/mobile-emulation
diff --git a/node_modules/selenium-webdriver/edge.js b/node_modules/selenium-webdriver/edge.js
index ee9d43383..9280cabd9 100644
--- a/node_modules/selenium-webdriver/edge.js
+++ b/node_modules/selenium-webdriver/edge.js
@@ -58,7 +58,7 @@
* var options = new edge.Options();
* // configure browser options ...
*
- * var driver = new edge.Driver(options, service);
+ * var driver = edge.Driver.createSession(options, service);
*
* Users should only instantiate the {@link Driver} class directly when they
* need a custom driver service configuration (as shown above). For normal
diff --git a/node_modules/selenium-webdriver/firefox/binary.js b/node_modules/selenium-webdriver/firefox/binary.js
index b997b480d..a1360bab7 100644
--- a/node_modules/selenium-webdriver/firefox/binary.js
+++ b/node_modules/selenium-webdriver/firefox/binary.js
@@ -47,27 +47,17 @@ const NO_FOCUS_LIB_AMD64 = isDevMode ?
const X_IGNORE_NO_FOCUS_LIB = 'x_ignore_nofocus.so';
-let foundBinary = null;
-let foundDevBinary = null;
-
-
/**
- * Checks the default Windows Firefox locations in Program Files.
- *
- * @param {boolean=} opt_dev Whether to find the Developer Edition.
+ * @param {string} file Path to the file to find, relative to the program files
+ * root.
* @return {!Promise<?string>} A promise for the located executable.
* The promise will resolve to {@code null} if Firefox was not found.
*/
-function defaultWindowsLocation(opt_dev) {
- var files = [
+function findInProgramFiles(file) {
+ let files = [
process.env['PROGRAMFILES'] || 'C:\\Program Files',
process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)'
- ].map(function(prefix) {
- if (opt_dev) {
- return path.join(prefix, 'Firefox Developer Edition\\firefox.exe');
- }
- return path.join(prefix, 'Mozilla Firefox\\firefox.exe');
- });
+ ].map(prefix => path.join(prefix, file));
return io.exists(files[0]).then(function(exists) {
return exists ? files[0] : io.exists(files[1]).then(function(exists) {
return exists ? files[1] : null;
@@ -77,49 +67,104 @@ function defaultWindowsLocation(opt_dev) {
/**
- * Locates the Firefox binary for the current system.
+ * Provides methods for locating the executable for a Firefox release channel
+ * on Windows and MacOS. For other systems (i.e. Linux), Firefox will always
+ * be located on the system PATH.
*
- * @param {boolean=} opt_dev Whether to find the Developer Edition. This only
- * used on Windows and OSX.
- * @return {!Promise<string>} A promise for the located binary. The promise will
- * be rejected if Firefox cannot be located.
+ * @final
*/
-function findFirefox(opt_dev) {
- if (opt_dev && foundDevBinary) {
- return foundDevBinary;
+class Channel {
+ /**
+ * @param {string} darwin The path to check when running on MacOS.
+ * @param {string} win32 The path to check when running on Windows.
+ */
+ constructor(darwin, win32) {
+ /** @private @const */ this.darwin_ = darwin;
+ /** @private @const */ this.win32_ = win32;
+ /** @private {Promise<string>} */
+ this.found_ = null;
}
- if (!opt_dev && foundBinary) {
- return foundBinary;
+ /**
+ * Attempts to locate the Firefox executable for this release channel. This
+ * will first check the default installation location for the channel before
+ * checking the user's PATH. The returned promise will be rejected if Firefox
+ * can not be found.
+ *
+ * @return {!Promise<string>} A promise for the location of the located
+ * Firefox executable.
+ */
+ locate() {
+ if (this.found_) {
+ return this.found_;
+ }
+
+ let found;
+ switch (process.platform) {
+ case 'darwin':
+ found = io.exists(this.darwin_)
+ .then(exists => exists ? this.darwin_ : io.findInPath('firefox'));
+ break;
+
+ case 'win32':
+ found = findInProgramFiles(this.win32_)
+ .then(found => found || io.findInPath('firefox.exe'));
+ break;
+
+ default:
+ found = Promise.resolve(io.findInPath('firefox'));
+ break;
+ }
+
+ this.found_ = found.then(found => {
+ if (found) {
+ // TODO: verify version info.
+ return found;
+ }
+ throw Error('Could not locate Firefox on the current system');
+ });
+ return this.found_;
}
+}
- let found;
- if (process.platform === 'darwin') {
- let exe = opt_dev
- ? '/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox-bin'
- : '/Applications/Firefox.app/Contents/MacOS/firefox-bin';
- found = io.exists(exe).then(exists => exists ? exe : null);
- } else if (process.platform === 'win32') {
- found = defaultWindowsLocation(opt_dev);
+/**
+ * Firefox's developer channel.
+ * @const
+ * @see <https://www.mozilla.org/en-US/firefox/channel/desktop/#aurora>
+ */
+Channel.AURORA = new Channel(
+ '/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox-bin',
+ 'Firefox Developer Edition\\firefox.exe');
- } else {
- found = Promise.resolve(io.findInPath('firefox'));
- }
+/**
+ * Firefox's beta channel. Note this is provided mainly for convenience as
+ * the beta channel has the same installation location as the main release
+ * channel.
+ * @const
+ * @see <https://www.mozilla.org/en-US/firefox/channel/desktop/#beta>
+ */
+Channel.BETA = new Channel(
+ '/Applications/Firefox.app/Contents/MacOS/firefox-bin',
+ 'Mozilla Firefox\\firefox.exe');
- found = found.then(found => {
- if (found) {
- return found;
- }
- throw Error('Could not locate Firefox on the current system');
- });
+/**
+ * Firefox's release channel.
+ * @const
+ * @see <https://www.mozilla.org/en-US/firefox/desktop/>
+ */
+Channel.RELEASE = new Channel(
+ '/Applications/Firefox.app/Contents/MacOS/firefox-bin',
+ 'Mozilla Firefox\\firefox.exe');
- if (opt_dev) {
- return foundDevBinary = found;
- } else {
- return foundBinary = found;
- }
-}
+/**
+ * Firefox's nightly release channel.
+ * @const
+ * @see <https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly>
+ */
+Channel.NIGHTLY = new Channel(
+ '/Applications/FirefoxNightly.app/Contents/MacOS/firefox-bin',
+ 'Nightly\\firefox.exe');
/**
@@ -151,20 +196,23 @@ function installNoFocusLibs(profileDir) {
* use with WebDriver.
*
* If created _without_ a path for the Firefox binary to use, this class will
- * attempt to find Firefox when {@link #launch()} is called. For OSX and
+ * attempt to find Firefox when {@link #launch()} is called. For MacOS and
* Windows, this class will look for Firefox in the current platform's default
- * installation location (e.g. /Applications/Firefox.app on OSX). For all other
- * platforms, the Firefox executable must be available on your system `PATH`.
+ * installation location (e.g. /Applications/Firefox.app on MacOS). For all
+ * other platforms, the Firefox executable must be available on your system
+ * `PATH`.
*
* @final
*/
class Binary {
/**
- * @param {string=} opt_exe Path to the Firefox binary to use.
+ * @param {?(string|Channel)=} opt_exeOrChannel Either the path to a specific
+ * Firefox binary to use, or a {@link Channel} instance that describes
+ * how to locate the desired Firefox version.
*/
- constructor(opt_exe) {
- /** @private {(string|undefined)} */
- this.exe_ = opt_exe;
+ constructor(opt_exeOrChannel) {
+ /** @private {?(string|Channel)} */
+ this.exe_ = opt_exeOrChannel || null;
/** @private {!Array.<string>} */
this.args_ = [];
@@ -187,7 +235,7 @@ class Binary {
* on the current system.
*/
getExe() {
- return this.exe_;
+ return typeof this.exe_ === 'string' ? this.exe_ : undefined;
}
/**
@@ -223,6 +271,8 @@ class Binary {
*
* @param {boolean=} opt_use Whether to use the developer edition. Defaults to
* true.
+ * @deprecated Use the {@link Channel} class to indicate the desired Firefox
+ * version when creating a new binary: `new Binary(Channel.AURORA)`.
*/
useDevEdition(opt_use) {
this.devEdition_ = opt_use === undefined || !!opt_use;
@@ -238,7 +288,13 @@ class Binary {
* used by this instance.
*/
locate() {
- return Promise.resolve(this.exe_ || findFirefox(this.devEdition_));
+ if (typeof this.exe_ === 'string') {
+ return Promise.resolve(this.exe_);
+ } else if (this.exe_ instanceof Channel) {
+ return this.exe_.locate();
+ }
+ let channel = this.devEdition_ ? Channel.AURORA : Channel.RELEASE;
+ return channel.locate();
}
/**
@@ -284,4 +340,5 @@ class Binary {
exports.Binary = Binary;
+exports.Channel = Channel;
diff --git a/node_modules/selenium-webdriver/firefox/extension.js b/node_modules/selenium-webdriver/firefox/extension.js
index 60abb06b8..3bda759a7 100644
--- a/node_modules/selenium-webdriver/firefox/extension.js
+++ b/node_modules/selenium-webdriver/firefox/extension.js
@@ -161,7 +161,7 @@ function readManifest(addonPath) {
manifest = io.stat(addonPath).then(function(stats) {
if (!stats.isDirectory()) {
throw Error(
- 'Add-on path is niether a xpi nor a directory: ' + addonPath);
+ 'Add-on path is neither a xpi nor a directory: ' + addonPath);
}
return io.read(path.join(addonPath, 'install.rdf'));
});
diff --git a/node_modules/selenium-webdriver/firefox/index.js b/node_modules/selenium-webdriver/firefox/index.js
index 4ea1702a9..d5c88274a 100644
--- a/node_modules/selenium-webdriver/firefox/index.js
+++ b/node_modules/selenium-webdriver/firefox/index.js
@@ -26,28 +26,31 @@
*
* __Customizing the Firefox Profile__
*
- * The {@link Profile} class may be used to configure the browser profile used
- * with WebDriver, with functions to install additional
+ * The {@linkplain Profile} class may be used to configure the browser profile
+ * used with WebDriver, with functions to install additional
* {@linkplain Profile#addExtension extensions}, configure browser
* {@linkplain Profile#setPreference preferences}, and more. For example, you
* may wish to include Firebug:
*
- * var firefox = require('selenium-webdriver/firefox');
+ * const {Builder} = require('selenium-webdriver');
+ * const firefox = require('selenium-webdriver/firefox');
*
- * var profile = new firefox.Profile();
+ * let profile = new firefox.Profile();
* profile.addExtension('/path/to/firebug.xpi');
* profile.setPreference('extensions.firebug.showChromeErrors', true);
*
- * var options = new firefox.Options().setProfile(profile);
- * var driver = new firefox.Driver(options);
+ * let options = new firefox.Options().setProfile(profile);
+ * let driver = new Builder()
+ * .forBrowser('firefox')
+ * .setFirefoxOptions(options)
+ * .build();
*
- * The {@link Profile} class may also be used to configure WebDriver based on a
- * pre-existing browser profile:
+ * The {@linkplain Profile} class may also be used to configure WebDriver based
+ * on a pre-existing browser profile:
*
- * var profile = new firefox.Profile(
+ * let profile = new firefox.Profile(
* '/usr/local/home/bob/.mozilla/firefox/3fgog75h.testing');
- * var options = new firefox.Options().setProfile(profile);
- * var driver = new firefox.Driver(options);
+ * let options = new firefox.Options().setProfile(profile);
*
* The FirefoxDriver will _never_ modify a pre-existing profile; instead it will
* create a copy for it to modify. By extension, there are certain browser
@@ -56,21 +59,35 @@
*
* __Using a Custom Firefox Binary__
*
- * On Windows and OSX, the FirefoxDriver will search for Firefox in its
+ * On Windows and MacOS, the FirefoxDriver will search for Firefox in its
* default installation location:
*
- * * Windows: C:\Program Files and C:\Program Files (x86).
- * * Mac OS X: /Applications/Firefox.app
+ * - Windows: C:\Program Files and C:\Program Files (x86).
+ * - MacOS: /Applications/Firefox.app
+ *
+ * For Linux, Firefox will always be located on the PATH: `$(where firefox)`.
*
- * For Linux, Firefox will be located on the PATH: `$(where firefox)`.
+ * Several methods are provided for starting Firefox with a custom executable.
+ * First, on Windows and MacOS, you may configure WebDriver to check the default
+ * install location for a non-release channel. If the requested channel cannot
+ * be found in its default location, WebDriver will fallback to searching your
+ * PATH. _Note:_ on Linux, Firefox is _always_ located on your path, regardless
+ * of the requested channel.
+ *
+ * const {Builder} = require('selenium-webdriver');
+ * const firefox = require('selenium-webdriver/firefox');
+ *
+ * let options = new firefox.Options().setBinary(firefox.Channel.NIGHTLY);
+ * let driver = new Builder()
+ * .forBrowser('firefox')
+ * .setFirefoxOptions(options)
+ * .build();
*
- * You can configure WebDriver to start use a custom Firefox installation with
- * the {@link Binary} class:
+ * On all platforms, you may configrue WebDriver to use a Firefox specific
+ * executable:
*
- * var firefox = require('selenium-webdriver/firefox');
- * var binary = new firefox.Binary('/my/firefox/install/dir/firefox-bin');
- * var options = new firefox.Options().setBinary(binary);
- * var driver = new firefox.Driver(options);
+ * let options = new firefox.Options()
+ * .setBinary('/my/firefox/install/dir/firefox-bin');
*
* __Remote Testing__
*
@@ -84,11 +101,14 @@
* binaries are never copied to remote machines and must be referenced by
* installation path.
*
- * var options = new firefox.Options()
+ * const {Builder} = require('selenium-webdriver');
+ * const firefox = require('selenium-webdriver/firefox');
+ *
+ * let options = new firefox.Options()
* .setProfile('/profile/path/on/remote/host')
* .setBinary('/install/dir/on/remote/host/firefox-bin');
*
- * var driver = new (require('selenium-webdriver')).Builder()
+ * let driver = new Builder()
* .forBrowser('firefox')
* .usingServer('http://127.0.0.1:4444/wd/hub')
* .setFirefoxOptions(options)
@@ -99,8 +119,7 @@
* To test versions of Firefox prior to Firefox 47, you must disable the use of
* the geckodriver using the {@link Options} class.
*
- * var options = new firefox.Options().useGeckoDriver(false);
- * var driver = new firefox.Driver(options);
+ * let options = new firefox.Options().useGeckoDriver(false);
*
* Alternatively, you may disable the geckodriver at runtime by setting the
* environment variable `SELENIUM_MARIONETTE=false`.
@@ -113,7 +132,7 @@
const url = require('url');
-const Binary = require('./binary').Binary,
+const {Binary, Channel} = require('./binary'),
Profile = require('./profile').Profile,
decodeProfile = require('./profile').decode,
http = require('../http'),
@@ -196,16 +215,24 @@ class Options {
}
/**
- * Sets the binary to use. The binary may be specified as the path to a Firefox
- * executable, or as a {@link Binary} object.
+ * Sets the binary to use. The binary may be specified as the path to a
+ * Firefox executable, a specific {@link Channel}, or as a {@link Binary}
+ * object.
*
- * @param {(string|!Binary)} binary The binary to use.
+ * @param {(string|!Binary|!Channel)} binary The binary to use.
* @return {!Options} A self reference.
+ * @throws {TypeError} If `binary` is an invalid type.
*/
setBinary(binary) {
- if (typeof binary === 'string') {
+ if (typeof binary === 'string' || binary instanceof Channel) {
binary = new Binary(binary);
}
+
+ if (!(binary instanceof Binary)) {
+ throw TypeError(
+ 'binary must be a string path, Channel, or Binary object');
+ }
+
this.binary_ = binary;
return this;
}
@@ -687,6 +714,7 @@ class Driver extends webdriver.WebDriver {
exports.Binary = Binary;
+exports.Channel = Channel;
exports.Context = Context;
exports.Driver = Driver;
exports.Options = Options;
diff --git a/node_modules/selenium-webdriver/index.js b/node_modules/selenium-webdriver/index.js
index 3cde7f396..a1e208b46 100644
--- a/node_modules/selenium-webdriver/index.js
+++ b/node_modules/selenium-webdriver/index.js
@@ -58,7 +58,7 @@ var seleniumServer;
* Starts an instance of the Selenium server if not yet running.
* @param {string} jar Path to the server jar to use.
* @return {!Promise<string>} A promise for the server's
- * addrss once started.
+ * address once started.
*/
function startSeleniumServer(jar) {
if (!seleniumServer) {
@@ -160,7 +160,7 @@ function createDriver(ctor, ...args) {
/** @override */
this.catch = pd.then.bind(pd);
}
- }
+ };
promise.CancellableThenable.addImplementation(thenableWebDriverProxy);
THENABLE_DRIVERS.set(ctor, thenableWebDriverProxy);
}
diff --git a/node_modules/selenium-webdriver/lib/README b/node_modules/selenium-webdriver/lib/README
index 583293864..c39abbece 100644
--- a/node_modules/selenium-webdriver/lib/README
+++ b/node_modules/selenium-webdriver/lib/README
@@ -1,6 +1,5 @@
This directory contains modules internal to selenium-webdriver that are not
intended for general consumption. They may change at any time.
-With the exception of the test/ directory, all files under this directory
-may only depend on built-in JavaScript features and other modules in the
-directory.
+All files in this directory and the atoms/ subdirectory may only depend on
+built-in JavaScript features and other modules in this directory.
diff --git a/node_modules/selenium-webdriver/lib/actions.js b/node_modules/selenium-webdriver/lib/actions.js
index 1b059bbbf..0e34f3783 100644
--- a/node_modules/selenium-webdriver/lib/actions.js
+++ b/node_modules/selenium-webdriver/lib/actions.js
@@ -128,7 +128,7 @@ class ActionSequence {
}
/**
- * Moves the mouse. The location to move to may be specified in terms of the
+ * Moves the mouse. The location to move to may be specified in terms of the
* mouse's current location, an offset relative to the top-left corner of an
* element, or an element (in which case the middle of the element is used).
*
@@ -333,7 +333,7 @@ class ActionSequence {
/**
* Performs a modifier key press. The modifier key is <em>not released</em>
* until {@link #keyUp} or {@link #sendKeys} is called. The key press will be
- * targetted at the currently focused element.
+ * targeted at the currently focused element.
*
* @param {!input.Key} key The modifier key to push. Must be one of
* {ALT, CONTROL, SHIFT, COMMAND, META}.
@@ -347,7 +347,7 @@ class ActionSequence {
}
/**
- * Performs a modifier key release. The release is targetted at the currently
+ * Performs a modifier key release. The release is targeted at the currently
* focused element.
* @param {!input.Key} key The modifier key to release. Must be one of
* {ALT, CONTROL, SHIFT, COMMAND, META}.
@@ -363,7 +363,7 @@ class ActionSequence {
/**
* Simulates typing multiple keys. Each modifier key encountered in the
* sequence will not be released until it is encountered again. All key events
- * will be targetted at the currently focused element.
+ * will be targeted at the currently focused element.
*
* @param {...(string|!input.Key|!Array<(string|!input.Key)>)} var_args
* The keys to type.
diff --git a/node_modules/selenium-webdriver/lib/by.js b/node_modules/selenium-webdriver/lib/by.js
index ac448e683..8c718be64 100644
--- a/node_modules/selenium-webdriver/lib/by.js
+++ b/node_modules/selenium-webdriver/lib/by.js
@@ -153,7 +153,7 @@ class By {
}
/**
- * Locates eleemnts by the ID attribute. This locator uses the CSS selector
+ * Locates elements by the ID attribute. This locator uses the CSS selector
* `*[id="$ID"]`, _not_ `document.getElementById`.
*
* @param {string} id The ID to search for.
diff --git a/node_modules/selenium-webdriver/lib/capabilities.js b/node_modules/selenium-webdriver/lib/capabilities.js
index 61396d54d..65b290f5f 100644
--- a/node_modules/selenium-webdriver/lib/capabilities.js
+++ b/node_modules/selenium-webdriver/lib/capabilities.js
@@ -103,7 +103,7 @@ const Capability = {
*/
PROXY: 'proxy',
- /** Whether the driver supports changing the brower's orientation. */
+ /** Whether the driver supports changing the browser's orientation. */
ROTATABLE: 'rotatable',
/**
@@ -130,7 +130,7 @@ const Capability = {
/**
* Defines how the driver should handle unexpected alerts. The value should
- * be one of "accept", "dismiss", or "ignore.
+ * be one of "accept", "dismiss", or "ignore".
*/
UNEXPECTED_ALERT_BEHAVIOR: 'unexpectedAlertBehavior',
@@ -367,7 +367,7 @@ class Capabilities extends Map {
/**
* Sets the logging preferences. Preferences may be specified as a
- * {@link ./logging.Preferences} instance, or a as a map of log-type to
+ * {@link ./logging.Preferences} instance, or as a map of log-type to
* log-level.
* @param {!(./logging.Preferences|Object<string>)} prefs The logging
* preferences.
@@ -408,7 +408,7 @@ class Capabilities extends Map {
/**
* Sets the default action to take with an unexpected alert before returning
* an error.
- * @param {string} behavior The desired behavior; should be "accept",
+ * @param {string} behavior The desired behavior should be "accept",
* "dismiss", or "ignore". Defaults to "dismiss".
* @return {!Capabilities} A self reference.
*/
diff --git a/node_modules/selenium-webdriver/lib/error.js b/node_modules/selenium-webdriver/lib/error.js
index 555e5cbc5..82f81b07c 100644
--- a/node_modules/selenium-webdriver/lib/error.js
+++ b/node_modules/selenium-webdriver/lib/error.js
@@ -311,7 +311,7 @@ class UnknownMethodError extends WebDriverError {
/**
- * Reports an unsupport operation.
+ * Reports an unsupported operation.
*/
class UnsupportedOperationError extends WebDriverError {
/** @param {string=} opt_error the error message, if any. */
@@ -462,17 +462,29 @@ function checkResponse(data) {
return data;
}
+/**
+ * Tests if the given value is a valid error response object according to the
+ * W3C WebDriver spec.
+ *
+ * @param {?} data The value to test.
+ * @return {boolean} Whether the given value data object is a valid error
+ * response.
+ * @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol
+ */
+function isErrorResponse(data) {
+ return data && typeof data === 'object' && typeof data.error === 'string';
+}
/**
* Throws an error coded from the W3C protocol. A generic error will be thrown
- * if the privded `data` is not a valid encoded error.
+ * if the provided `data` is not a valid encoded error.
*
* @param {{error: string, message: string}} data The error data to decode.
* @throws {WebDriverError} the decoded error.
* @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol
*/
function throwDecodedError(data) {
- if (data && typeof data === 'object' && typeof data.error === 'string') {
+ if (isErrorResponse(data)) {
let ctor = ERROR_CODE_TO_TYPE.get(data.error) || WebDriverError;
throw new ctor(data.message);
}
@@ -551,5 +563,6 @@ module.exports = {
checkResponse: checkResponse,
checkLegacyResponse: checkLegacyResponse,
encodeError: encodeError,
+ isErrorResponse: isErrorResponse,
throwDecodedError: throwDecodedError,
};
diff --git a/node_modules/selenium-webdriver/lib/events.js b/node_modules/selenium-webdriver/lib/events.js
index 65e63de8c..82b34803e 100644
--- a/node_modules/selenium-webdriver/lib/events.js
+++ b/node_modules/selenium-webdriver/lib/events.js
@@ -22,7 +22,7 @@
*/
class Listener {
/**
- * @param {!Function} fn The acutal listener function.
+ * @param {!Function} fn The actual listener function.
* @param {(Object|undefined)} scope The object in whose scope to invoke the
* listener.
* @param {boolean} oneshot Whether this listener should only be used once.
diff --git a/node_modules/selenium-webdriver/lib/firefox/amd64/libnoblur64.so b/node_modules/selenium-webdriver/lib/firefox/amd64/libnoblur64.so
deleted file mode 100644
index 248c32db5..000000000
--- a/node_modules/selenium-webdriver/lib/firefox/amd64/libnoblur64.so
+++ /dev/null
Binary files differ
diff --git a/node_modules/selenium-webdriver/lib/firefox/i386/libnoblur.so b/node_modules/selenium-webdriver/lib/firefox/i386/libnoblur.so
deleted file mode 100644
index 004062c7b..000000000
--- a/node_modules/selenium-webdriver/lib/firefox/i386/libnoblur.so
+++ /dev/null
Binary files differ
diff --git a/node_modules/selenium-webdriver/lib/firefox/webdriver.json b/node_modules/selenium-webdriver/lib/firefox/webdriver.json
index 38601a28c..0dbe56bbd 100644
--- a/node_modules/selenium-webdriver/lib/firefox/webdriver.json
+++ b/node_modules/selenium-webdriver/lib/firefox/webdriver.json
@@ -37,7 +37,6 @@
"network.http.phishy-userpass-length": 255,
"offline-apps.allow_by_default": true,
"prompts.tab_modal.enabled": false,
- "security.csp.enable": false,
"security.fileuri.origin_policy": 3,
"security.fileuri.strict_origin_policy": false,
"signon.rememberSignons": false,
@@ -61,6 +60,8 @@
"dom.max_script_run_time": 30,
"dom.report_all_js_exceptions": true,
"javascript.options.showInConsole": true,
+ "network.captive-portal-service.enabled": false,
+ "security.csp.enable": false,
"startup.homepage_welcome_url": "about:blank",
"startup.homepage_welcome_url.additional": "about:blank",
"webdriver_accept_untrusted_certs": true,
diff --git a/node_modules/selenium-webdriver/lib/firefox/webdriver.xpi b/node_modules/selenium-webdriver/lib/firefox/webdriver.xpi
index f9a51cf4f..a7b0fa3a7 100644
--- a/node_modules/selenium-webdriver/lib/firefox/webdriver.xpi
+++ b/node_modules/selenium-webdriver/lib/firefox/webdriver.xpi
Binary files differ
diff --git a/node_modules/selenium-webdriver/lib/http.js b/node_modules/selenium-webdriver/lib/http.js
index 68bc43213..136a48e63 100644
--- a/node_modules/selenium-webdriver/lib/http.js
+++ b/node_modules/selenium-webdriver/lib/http.js
@@ -25,17 +25,26 @@
'use strict';
-const fs = require('fs');
-const path = require('path');
-
const cmd = require('./command');
-const devmode = require('./devmode');
const error = require('./error');
const logging = require('./logging');
const promise = require('./promise');
const Session = require('./session').Session;
const WebElement = require('./webdriver').WebElement;
+const {getAttribute, isDisplayed} = (function() {
+ try {
+ return {
+ getAttribute: require('./atoms/getAttribute.js'),
+ isDisplayed: require('./atoms/is-displayed.js')
+ };
+ } catch (ex) {
+ throw Error(
+ 'Failed to import atoms modules. If running in devmode, you need to run'
+ + ' `./go node:atoms` from the project root: ' + ex);
+ }
+})();
+
/**
* Converts a headers map to a HTTP header block string.
@@ -116,43 +125,15 @@ class Response {
const DEV_ROOT = '../../../../buck-out/gen/javascript/';
-/** @enum {string} */
+/** @enum {!Function} */
const Atom = {
- GET_ATTRIBUTE: devmode
- ? path.join(__dirname, DEV_ROOT, 'webdriver/atoms/getAttribute.js')
- : path.join(__dirname, 'atoms/getAttribute.js'),
- IS_DISPLAYED: devmode
- ? path.join(__dirname, DEV_ROOT, 'atoms/fragments/is-displayed.js')
- : path.join(__dirname, 'atoms/isDisplayed.js'),
+ GET_ATTRIBUTE: getAttribute,
+ IS_DISPLAYED: isDisplayed
};
-const ATOMS = /** !Map<string, !Promise<string>> */new Map();
const LOG = logging.getLogger('webdriver.http');
-/**
- * @param {Atom} file The atom file to load.
- * @return {!Promise<string>} A promise that will resolve to the contents of the
- * file.
- */
-function loadAtom(file) {
- if (ATOMS.has(file)) {
- return ATOMS.get(file);
- }
- let contents = /** !Promise<string> */new Promise((resolve, reject) => {
- LOG.finest(() => `Loading atom ${file}`);
- fs.readFile(file, 'utf8', function(err, data) {
- if (err) {
- reject(err);
- } else {
- resolve(data);
- }
- });
- });
- ATOMS.set(file, contents);
- return contents;
-}
-
function post(path) { return resource('POST', path); }
function del(path) { return resource('DELETE', path); }
@@ -168,17 +149,26 @@ var CommandSpec;
var CommandTransformer;
+class InternalTypeError extends TypeError {}
+
+
/**
* @param {!cmd.Command} command The initial command.
* @param {Atom} atom The name of the atom to execute.
* @return {!Promise<!cmd.Command>} The transformed command to execute.
*/
function toExecuteAtomCommand(command, atom, ...params) {
- return loadAtom(atom).then(atom => {
- return new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
+ return new Promise((resolve, reject) => {
+ if (typeof atom !== 'function') {
+ reject(new InternalTypeError('atom is not a function: ' + typeof atom));
+ return;
+ }
+
+ let newCmd = new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
.setParameter('sessionId', command.getParameter('sessionId'))
.setParameter('script', `return (${atom}).apply(null, arguments)`)
.setParameter('args', params.map(param => command.getParameter(param)));
+ resolve(newCmd);
});
}
@@ -269,6 +259,8 @@ const W3C_COMMAND_MAP = new Map([
[cmd.Name.GET_ELEMENT_ATTRIBUTE, (cmd) => {
return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name');
}],
+ [cmd.Name.GET_ELEMENT_LOCATION, get('/session/:sessionId/element/:id/rect')],
+ [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/rect')],
[cmd.Name.IS_ELEMENT_DISPLAYED, (cmd) => {
return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id');
}],
@@ -437,7 +429,8 @@ class Executor {
this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
let parsed =
- parseHttpResponse(/** @type {!Response} */ (response), this.w3c);
+ parseHttpResponse(
+ command, /** @type {!Response} */ (response), this.w3c);
if (command.getName() === cmd.Name.NEW_SESSION
|| command.getName() === cmd.Name.DESCRIBE_SESSION) {
@@ -447,7 +440,7 @@ class Executor {
}
// The remote end is a W3C compliant server if there is no `status`
- // field in the response. This is not appliable for the DESCRIBE_SESSION
+ // field in the response. This is not applicable for the DESCRIBE_SESSION
// command, which is not defined in the W3C spec.
if (command.getName() === cmd.Name.NEW_SESSION) {
this.w3c = this.w3c || !('status' in parsed);
@@ -485,29 +478,42 @@ function tryParse(str) {
/**
* Callback used to parse {@link Response} objects from a
* {@link HttpClient}.
+ *
+ * @param {!cmd.Command} command The command the response is for.
* @param {!Response} httpResponse The HTTP response to parse.
* @param {boolean} w3c Whether the response should be processed using the
* W3C wire protocol.
* @return {?} The parsed response.
* @throws {WebDriverError} If the HTTP response is an error.
*/
-function parseHttpResponse(httpResponse, w3c) {
+function parseHttpResponse(command, httpResponse, w3c) {
let parsed = tryParse(httpResponse.body);
if (parsed !== undefined) {
+ if (httpResponse.status < 200) {
+ // This should never happen, but throw the raw response so
+ // users report it.
+ throw new error.WebDriverError(
+ `Unexpected HTTP response:\n${httpResponse}`);
+ }
+
if (w3c) {
if (httpResponse.status > 399) {
error.throwDecodedError(parsed);
}
+ return parsed;
+ }
- if (httpResponse.status < 200) {
- // This should never happen, but throw the raw response so
- // users report it.
- throw new error.WebDriverError(
- `Unexpected HTTP response:\n${httpResponse}`);
- }
- } else {
- error.checkLegacyResponse(parsed);
+ // If this is a new session command, we need to check for a W3C compliant
+ // error object. This is necessary since a successful new session command
+ // is what puts the executor into W3C mode.
+ if (httpResponse.status > 399
+ && (command.getName() == cmd.Name.NEW_SESSION
+ || command.getName() === cmd.Name.DESCRIBE_SESSION)
+ && error.isErrorResponse(parsed)) {
+ error.throwDecodedError(parsed);
}
+
+ error.checkLegacyResponse(parsed);
return parsed;
}
diff --git a/node_modules/selenium-webdriver/lib/input.js b/node_modules/selenium-webdriver/lib/input.js
index 058530ebc..4ea938d45 100644
--- a/node_modules/selenium-webdriver/lib/input.js
+++ b/node_modules/selenium-webdriver/lib/input.js
@@ -144,7 +144,7 @@ class FileDetector {
/**
* Handles the file specified by the given path, preparing it for use with
* the current browser. If the path does not refer to a valid file, it will
- * be returned unchanged, otherwisee a path suitable for use with the current
+ * be returned unchanged, otherwise a path suitable for use with the current
* browser will be returned.
*
* This default implementation is a no-op. Subtypes may override this function
diff --git a/node_modules/selenium-webdriver/lib/promise.js b/node_modules/selenium-webdriver/lib/promise.js
index 32d0c98e6..b26cd23ff 100644
--- a/node_modules/selenium-webdriver/lib/promise.js
+++ b/node_modules/selenium-webdriver/lib/promise.js
@@ -48,7 +48,7 @@
* > e => console.error('FAILURE: ' + e));
* > ```
* >
- * > The motiviation behind this change and full deprecation plan are documented
+ * > The motivation behind this change and full deprecation plan are documented
* > in [issue 2969](https://github.com/SeleniumHQ/selenium/issues/2969).
* >
* >
@@ -87,8 +87,7 @@
* The control flow is based on the concept of tasks and task queues. Tasks are
* functions that define the basic unit of work for the control flow to execute.
* Each task is scheduled via {@link ControlFlow#execute()}, which will return
- * a {@link ManagedPromise ManagedPromise} that will be resolved with the task's
- * result.
+ * a {@link ManagedPromise} that will be resolved with the task's result.
*
* A task queue contains all of the tasks scheduled within a single turn of the
* [JavaScript event loop][JSEL]. The control flow will create a new task queue
@@ -103,13 +102,13 @@
*
* Whenever the control flow creates a new task queue, it will automatically
* begin executing tasks in the next available turn of the event loop. This
- * execution is scheduled using a "micro-task" timer, such as a (native)
- * `ManagedPromise.then()` callback.
+ * execution is [scheduled as a microtask][MicrotasksArticle] like e.g. a
+ * (native) `Promise.then()` callback.
*
* setTimeout(() => console.log('a'));
- * ManagedPromise.resolve().then(() => console.log('b')); // A native promise.
+ * Promise.resolve().then(() => console.log('b')); // A native promise.
* flow.execute(() => console.log('c'));
- * ManagedPromise.resolve().then(() => console.log('d'));
+ * Promise.resolve().then(() => console.log('d'));
* setTimeout(() => console.log('fin'));
* // b
* // c
@@ -118,13 +117,13 @@
* // fin
*
* In the example above, b/c/d is logged before a/fin because native promises
- * and this module use "micro-task" timers, which have a higher priority than
- * "macro-tasks" like `setTimeout`.
+ * and this module use "microtask" timers, which have a higher priority than
+ * "macrotasks" like `setTimeout`.
*
* ## Task Execution
*
- * Upon creating a task queue, and whenever an exisiting queue completes a task,
- * the control flow will schedule a micro-task timer to process any scheduled
+ * Upon creating a task queue, and whenever an existing queue completes a task,
+ * the control flow will schedule a microtask timer to process any scheduled
* tasks. This ensures no task is ever started within the same turn of the
* JavaScript event loop in which it was scheduled, nor is a task ever started
* within the same turn that another finishes.
@@ -140,13 +139,13 @@
* discarded and the task's promised result (previously returned by
* {@link ControlFlow#execute()}) is immediately rejected with the thrown
* error.
- * 3. The task function returns sucessfully.
+ * 3. The task function returns successfully.
*
* If a task function created a new task queue, the control flow will wait for
* that queue to complete before processing the task result. If the queue
* completes without error, the flow will settle the task's promise with the
- * value originaly returned by the task function. On the other hand, if the task
- * queue termintes with an error, the task's promise will be rejected with that
+ * value originally returned by the task function. On the other hand, if the task
+ * queue terminates with an error, the task's promise will be rejected with that
* error.
*
* flow.execute(function() {
@@ -161,7 +160,7 @@
* ## ManagedPromise Integration
*
* In addition to the {@link ControlFlow} class, the promise module also exports
- * a [ManagedPromise/A+] {@linkplain ManagedPromise implementation} that is deeply
+ * a [Promises/A+] {@linkplain ManagedPromise implementation} that is deeply
* integrated with the ControlFlow. First and foremost, each promise
* {@linkplain ManagedPromise#then() callback} is scheduled with the
* control flow as a task. As a result, each callback is invoked in its own turn
@@ -328,7 +327,7 @@
* Even though a subtask's promised result will never resolve while the task
* function is on the stack, it will be treated as a promise resolved within the
* task. In all other scenarios, a task's promise behaves just like a normal
- * promise. In the sample below, `C/D` is loggged before `B` because the
+ * promise. In the sample below, `C/D` is logged before `B` because the
* resolution of `subtask1` interrupts the flow of the enclosing task. Within
* the final subtask, `E/F` is logged in order because `subtask1` is a resolved
* promise when that task runs.
@@ -467,17 +466,17 @@
*
* ES6 promises do not require users to handle a promise rejections. This can
* result in subtle bugs as the rejections are silently "swallowed" by the
- * ManagedPromise class.
+ * Promise class.
*
- * ManagedPromise.reject(Error('boom'));
+ * Promise.reject(Error('boom'));
* // ... *crickets* ...
*
* Selenium's promise module, on the other hand, requires that every rejection
* be explicitly handled. When a {@linkplain ManagedPromise ManagedPromise} is
* rejected and no callbacks are defined on that promise, it is considered an
- * _unhandled rejection_ and reproted to the active task queue. If the rejection
+ * _unhandled rejection_ and reported to the active task queue. If the rejection
* remains unhandled after a single turn of the [event loop][JSEL] (scheduled
- * with a micro-task), it will propagate up the stack.
+ * with a microtask), it will propagate up the stack.
*
* ## Error Propagation
*
@@ -534,7 +533,7 @@
*
* When a subtask is discarded due to an unreported rejection in its parent
* frame, the existing callbacks on that task will never settle and the
- * callbacks will not be invoked. If a new callback is attached ot the subtask
+ * callbacks will not be invoked. If a new callback is attached to the subtask
* _after_ it has been discarded, it is handled the same as adding a callback
* to a cancelled promise: the error-callback path is invoked. This behavior is
* intended to handle cases where the user saves a reference to a task promise,
@@ -582,9 +581,9 @@
*
* Bottom line: you __*must*__ handle rejected promises.
*
- * # ManagedPromise/A+ Compatibility
+ * # Promises/A+ Compatibility
*
- * This `promise` module is compliant with the [ManagedPromise/A+][] specification
+ * This `promise` module is compliant with the [Promises/A+] specification
* except for sections `2.2.6.1` and `2.2.6.2`:
*
* >
@@ -595,10 +594,10 @@
* > must execute in the order of their originating calls to `then`.
* >
*
- * Specifically, the conformance tests contains the following scenario (for
+ * Specifically, the conformance tests contain the following scenario (for
* brevity, only the fulfillment version is shown):
*
- * var p1 = ManagedPromise.resolve();
+ * var p1 = Promise.resolve();
* p1.then(function() {
* console.log('A');
* p1.then(() => console.log('B'));
@@ -609,7 +608,7 @@
* // B
*
* Since the [ControlFlow](#scheduling_callbacks) executes promise callbacks as
- * tasks, with this module, the result would be
+ * tasks, with this module, the result would be:
*
* var p2 = promise.fulfilled();
* p2.then(function() {
@@ -623,7 +622,8 @@
*
* [JSEL]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
* [GF]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
- * [ManagedPromise/A+]: https://promisesaplus.com/
+ * [Promises/A+]: https://promisesaplus.com/
+ * [MicrotasksArticle]: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
*/
'use strict';
@@ -667,7 +667,7 @@ function getUid(obj) {
/**
- * Runs the given function after a micro-task yield.
+ * Runs the given function after a microtask yield.
* @param {function()} fn The function to run.
*/
function asyncRun(fn) {
@@ -942,7 +942,7 @@ class Thenable {
/**
* Marker interface for objects that allow consumers to request the cancellation
- * of a promies-based operation. A cancelled promise will be rejected with a
+ * of a promise-based operation. A cancelled promise will be rejected with a
* {@link CancellationError}.
*
* This interface is considered package-private and should not be used outside
@@ -1003,6 +1003,9 @@ const PromiseState = {
*/
const ON_CANCEL_HANDLER = new WeakMap;
+const SKIP_LOG = Symbol('skip-log');
+const FLOW_LOG = logging.getLogger('promise.ControlFlow');
+
/**
* Represents the eventual value of a completed operation. Each promise may be
@@ -1025,14 +1028,29 @@ class ManagedPromise {
* functions, one for fulfilling the promise and another for rejecting it.
* @param {ControlFlow=} opt_flow The control flow
* this instance was created under. Defaults to the currently active flow.
+ * @param {?=} opt_skipLog An internal parameter used to skip logging the
+ * creation of this promise. This parameter has no effect unless it is
+ * strictly equal to an internal symbol. In other words, this parameter
+ * is always ignored for external code.
*/
- constructor(resolver, opt_flow) {
+ constructor(resolver, opt_flow, opt_skipLog) {
if (!usePromiseManager()) {
throw TypeError(
'Unable to create a managed promise instance: the promise manager has'
+ ' been disabled by the SELENIUM_PROMISE_MANAGER environment'
+ ' variable: ' + process.env['SELENIUM_PROMISE_MANAGER']);
+ } else if (opt_skipLog !== SKIP_LOG) {
+ FLOW_LOG.warning(() => {
+ let e =
+ captureStackTrace(
+ 'ManagedPromiseError',
+ 'Creating a new managed Promise. This call will fail when the'
+ + ' promise manager is disabled',
+ ManagedPromise)
+ return e.stack;
+ });
}
+
getUid(this);
/** @private {!ControlFlow} */
@@ -1308,7 +1326,7 @@ class ManagedPromise {
* @param {!Function} fn The function to use as the top of the stack when
* recording the callback's creation point.
* @return {!ManagedPromise<R>} A new promise which will be resolved with the
- * esult of the invoked callback.
+ * result of the invoked callback.
* @template R
* @private
*/
@@ -1384,6 +1402,37 @@ function isPending(promise) {
/**
+ * Structural interface for a deferred promise resolver.
+ * @record
+ * @template T
+ */
+function Resolver() {}
+
+
+/**
+ * The promised value for this resolver.
+ * @type {!Thenable<T>}
+ */
+Resolver.prototype.promise;
+
+
+/**
+ * Resolves the promised value with the given `value`.
+ * @param {T|Thenable<T>} value
+ * @return {void}
+ */
+Resolver.prototype.resolve;
+
+
+/**
+ * Rejects the promised value with the given `reason`.
+ * @param {*} reason
+ * @return {void}
+ */
+Resolver.prototype.reject;
+
+
+/**
* Represents a value that will be resolved at some point in the future. This
* class represents the protected "producer" half of a ManagedPromise - each Deferred
* has a {@code promise} property that may be returned to consumers for
@@ -1395,20 +1444,25 @@ function isPending(promise) {
* {@link ControlFlow} as an unhandled failure.
*
* @template T
+ * @implements {Resolver<T>}
*/
class Deferred {
/**
* @param {ControlFlow=} opt_flow The control flow this instance was
* created under. This should only be provided during unit tests.
+ * @param {?=} opt_skipLog An internal parameter used to skip logging the
+ * creation of this promise. This parameter has no effect unless it is
+ * strictly equal to an internal symbol. In other words, this parameter
+ * is always ignored for external code.
*/
- constructor(opt_flow) {
+ constructor(opt_flow, opt_skipLog) {
var fulfill, reject;
/** @type {!ManagedPromise<T>} */
this.promise = new ManagedPromise(function(f, r) {
fulfill = f;
reject = r;
- }, opt_flow);
+ }, opt_flow, opt_skipLog);
var self = this;
var checkNotSelf = function(value) {
@@ -1421,16 +1475,24 @@ class Deferred {
* Resolves this deferred with the given value. It is safe to call this as a
* normal function (with no bound "this").
* @param {(T|IThenable<T>|Thenable)=} opt_value The fulfilled value.
+ * @const
*/
- this.fulfill = function(opt_value) {
+ this.resolve = function(opt_value) {
checkNotSelf(opt_value);
fulfill(opt_value);
};
/**
+ * An alias for {@link #resolve}.
+ * @const
+ */
+ this.fulfill = this.resolve;
+
+ /**
* Rejects this promise with the given reason. It is safe to call this as a
* normal function (with no bound "this").
* @param {*=} opt_reason The rejection reason.
+ * @const
*/
this.reject = function(opt_reason) {
checkNotSelf(opt_reason);
@@ -1487,36 +1549,76 @@ function delayed(ms) {
/**
- * Creates a new deferred object.
- * @return {!Deferred<T>} The new deferred object.
+ * Creates a new deferred resolver.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@link Deferred} instance. Otherwise, it will return a resolver for a
+ * {@linkplain NativePromise native promise}.
+ *
+ * @return {!Resolver<T>} A new deferred resolver.
* @template T
*/
function defer() {
- return new Deferred();
+ if (usePromiseManager()) {
+ return new Deferred();
+ }
+ let resolve, reject;
+ let promise = new NativePromise((_resolve, _reject) => {
+ resolve = _resolve;
+ reject = _reject;
+ });
+ return {promise, resolve, reject};
}
/**
* Creates a promise that has been resolved with the given value.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
+ * {@linkplain NativePromise native promise}.
+ *
* @param {T=} opt_value The resolved value.
- * @return {!ManagedPromise<T>} The resolved promise.
- * @deprecated Use {@link ManagedPromise#resolve Promise.resolve(value)}.
+ * @return {!Thenable<T>} The resolved promise.
* @template T
*/
function fulfilled(opt_value) {
- return ManagedPromise.resolve(opt_value);
+ let ctor = usePromiseManager() ? ManagedPromise : NativePromise;
+ if (opt_value instanceof ctor) {
+ return /** @type {!Thenable} */(opt_value);
+ }
+
+ if (usePromiseManager()) {
+ // We can skip logging warnings about creating a managed promise because
+ // this function will automatically switch to use a native promise when
+ // the promise manager is disabled.
+ return new ManagedPromise(
+ resolve => resolve(opt_value), undefined, SKIP_LOG);
+ }
+ return NativePromise.resolve(opt_value);
}
/**
* Creates a promise that has been rejected with the given reason.
+ *
+ * If the promise manager is currently enabled, this function will return a
+ * {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
+ * {@linkplain NativePromise native promise}.
+ *
* @param {*=} opt_reason The rejection reason; may be any value, but is
* usually an Error or a string.
- * @return {!ManagedPromise<?>} The rejected promise.
- * @deprecated Use {@link ManagedPromise#reject Promise.reject(reason)}.
+ * @return {!Thenable<?>} The rejected promise.
*/
function rejected(opt_reason) {
- return ManagedPromise.reject(opt_reason);
+ if (usePromiseManager()) {
+ // We can skip logging warnings about creating a managed promise because
+ // this function will automatically switch to use a native promise when
+ // the promise manager is disabled.
+ return new ManagedPromise(
+ (_, reject) => reject(opt_reason), undefined, SKIP_LOG);
+ }
+ return NativePromise.reject(opt_reason);
}
@@ -1610,21 +1712,17 @@ function thenFinally(promise, callback) {
* @param {Function=} opt_errback The function to call when the value is
* rejected.
* @return {!Thenable} A new promise.
+ * @deprecated Use `promise.fulfilled(value).then(opt_callback, opt_errback)`
*/
function when(value, opt_callback, opt_errback) {
- if (Thenable.isImplementation(value)) {
- return value.then(opt_callback, opt_errback);
- }
-
- return createPromise(resolve => resolve(value))
- .then(opt_callback, opt_errback);
+ return fulfilled(value).then(opt_callback, opt_errback);
}
/**
* Invokes the appropriate callback function as soon as a promised `value` is
- * resolved. This function is similar to `when()`, except it does not return
- * a new promise.
+ * resolved.
+ *
* @param {*} value The value to observe.
* @param {Function} callback The function to call when the value is
* resolved successfully.
@@ -1826,7 +1924,7 @@ function filter(arr, fn, opt_self) {
*/
function fullyResolved(value) {
if (isPromise(value)) {
- return when(value, fullyResolveValue);
+ return fulfilled(value).then(fullyResolveValue);
}
return fullyResolveValue(value);
}
@@ -1973,7 +2071,7 @@ class Scheduler {
/**
* Schedules a task to wait for a condition to hold.
*
- * If the condition is defined as a function, it may return any value. Promies
+ * If the condition is defined as a function, it may return any value. Promise
* will be resolved before testing if the condition holds (resolution time
* counts towards the timeout). Once resolved, values are always evaluated as
* booleans.
@@ -1997,7 +2095,7 @@ class Scheduler {
* @param {string=} opt_message An optional error message to include if the
* wait times out; defaults to the empty string.
* @return {!Thenable<T>} A promise that will be fulfilled
- * when the condition has been satisified. The promise shall be rejected
+ * when the condition has been satisfied. The promise shall be rejected
* if the wait times out waiting for the condition.
* @throws {TypeError} If condition is not a function or promise or if timeout
* is not a number >= 0.
@@ -2018,6 +2116,10 @@ function usePromiseManager() {
/**
+ * Creates a new promise with the given `resolver` function. If the promise
+ * manager is currently enabled, the returned promise will be a
+ * {@linkplain ManagedPromise} instance. Otherwise, it will be a native promise.
+ *
* @param {function(
* function((T|IThenable<T>|Thenable|null)=),
* function(*=))} resolver
@@ -2040,7 +2142,7 @@ function createPromise(resolver) {
* @param {string=} opt_message An optional error message to include if the
* wait times out; defaults to the empty string.
* @return {!Thenable<T>} A promise that will be fulfilled
- * when the condition has been satisified. The promise shall be rejected
+ * when the condition has been satisfied. The promise shall be rejected
* if the wait times out waiting for the condition.
* @throws {TypeError} If condition is not a function or promise or if timeout
* is not a number >= 0.
@@ -2164,7 +2266,7 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
/**
* Handles the execution of scheduled tasks, each of which may be an
* asynchronous operation. The control flow will ensure tasks are executed in
- * the ordered scheduled, starting each task only once those before it have
+ * the order scheduled, starting each task only once those before it have
* completed.
*
* Each task scheduled within this flow may return a {@link ManagedPromise} to
@@ -2172,21 +2274,21 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
* promises to be resolved before marking the task as completed.
*
* Tasks and each callback registered on a {@link ManagedPromise} will be run
- * in their own ControlFlow frame. Any tasks scheduled within a frame will take
+ * in their own ControlFlow frame. Any tasks scheduled within a frame will take
* priority over previously scheduled tasks. Furthermore, if any of the tasks in
* the frame fail, the remainder of the tasks in that frame will be discarded
* and the failure will be propagated to the user through the callback/task's
* promised result.
*
* Each time a ControlFlow empties its task queue, it will fire an
- * {@link ControlFlow.EventType.IDLE IDLE} event. Conversely,
- * whenever the flow terminates due to an unhandled error, it will remove all
+ * {@link ControlFlow.EventType.IDLE IDLE} event. Conversely, whenever
+ * the flow terminates due to an unhandled error, it will remove all
* remaining tasks in its queue and fire an
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION UNCAUGHT_EXCEPTION} event.
* If there are no listeners registered with the flow, the error will be
* rethrown to the global error handler.
*
- * Refer to the {@link ./promise} module documentation for a detailed
+ * Refer to the {@link ./promise} module documentation for a detailed
* explanation of how the ControlFlow coordinates task execution.
*
* @implements {Scheduler}
@@ -2212,7 +2314,7 @@ class ControlFlow extends events.EventEmitter {
this.taskQueues_ = null;
/**
- * Micro task that controls shutting down the control flow. Upon shut down,
+ * Microtask that controls shutting down the control flow. Upon shut down,
* the flow will emit an
* {@link ControlFlow.EventType.IDLE} event. Idle events
* always follow a brief timeout in order to catch latent errors from the
@@ -2221,8 +2323,8 @@ class ControlFlow extends events.EventEmitter {
* by the promise system until the next turn of the event loop:
*
* // Schedule 1 task that fails.
- * var result = promise.controlFlow().schedule('example',
- * function() { return promise.rejected('failed'); });
+ * var result = promise.controlFlow().execute(
+ * () => promise.rejected('failed'), 'example');
* // Set a callback on the result. This delays reporting the unhandled
* // failure for 1 turn of the event loop.
* result.then(function() {});
@@ -2246,7 +2348,7 @@ class ControlFlow extends events.EventEmitter {
/**
* Returns a string representation of this control flow, which is its current
* {@linkplain #getSchedule() schedule}, sans task stack traces.
- * @return {string} The string representation of this contorl flow.
+ * @return {string} The string representation of this control flow.
* @override
*/
toString() {
@@ -2258,8 +2360,7 @@ class ControlFlow extends events.EventEmitter {
* control flow stack and cause rejections within parent tasks. If error
* propagation is disabled, tasks will not be aborted when an unhandled
* promise rejection is detected, but the rejection _will_ trigger an
- * {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION}
- * event.
+ * {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
*
* The default behavior is to propagate all unhandled rejections. _The use
* of this option is highly discouraged._
@@ -2293,7 +2394,7 @@ class ControlFlow extends events.EventEmitter {
* {@code opt_includeStackTraces === true}, the string will include the
* stack trace from when each task was scheduled.
* @param {string=} opt_includeStackTraces Whether to include the stack traces
- * from when each task was scheduled. Defaults to false.
+ * from when each task was scheduled. Defaults to false.
* @return {string} String representation of this flow's internal state.
*/
getSchedule(opt_includeStackTraces) {
@@ -2345,7 +2446,7 @@ class ControlFlow extends events.EventEmitter {
}
/**
- * Returns the currently actively task queue for this flow. If there is no
+ * Returns the currently active task queue for this flow. If there is no
* active queue, one will be created.
* @return {!TaskQueue} the currently active task queue for this flow.
* @private
@@ -2377,15 +2478,31 @@ class ControlFlow extends events.EventEmitter {
}
if (!this.hold_) {
- var holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
+ let holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
this.hold_ = setInterval(function() {}, holdIntervalMs);
}
- var task = new Task(
+ let task = new Task(
this, fn, opt_description || '<anonymous>',
- {name: 'Task', top: ControlFlow.prototype.execute});
+ {name: 'Task', top: ControlFlow.prototype.execute},
+ true);
+
+ let q = this.getActiveQueue_();
+
+ for (let i = q.tasks_.length; i > 0; i--) {
+ let previousTask = q.tasks_[i - 1];
+ if (previousTask.userTask_) {
+ FLOW_LOG.warning(() => {
+ return `Detected scheduling of an unchained task.
+When the promise manager is disabled, unchained tasks will not wait for
+previously scheduled tasks to finish before starting to execute.
+New task: ${task.promise.stack_.stack}
+Previous task: ${previousTask.promise.stack_.stack}`.split(/\n/).join('\n ');
+ });
+ break;
+ }
+ }
- var q = this.getActiveQueue_();
q.enqueue(task);
this.emit(ControlFlow.EventType.SCHEDULE_TASK, task.description);
return task.promise;
@@ -2393,7 +2510,7 @@ class ControlFlow extends events.EventEmitter {
/** @override */
promise(resolver) {
- return new ManagedPromise(resolver, this);
+ return new ManagedPromise(resolver, this, SKIP_LOG);
}
/** @override */
@@ -2622,7 +2739,7 @@ class MicroTask {
}
/**
- * Runs the given function after a micro-task yield.
+ * Runs the given function after a microtask yield.
* @param {function()} fn The function to run.
*/
static run(fn) {
@@ -2662,9 +2779,11 @@ class Task extends Deferred {
* @param {string} description A description of the task for debugging.
* @param {{name: string, top: !Function}=} opt_stackOptions Options to use
* when capturing the stacktrace for when this task was created.
+ * @param {boolean=} opt_isUserTask Whether this task was explicitly scheduled
+ * by the use of the promise manager.
*/
- constructor(flow, fn, description, opt_stackOptions) {
- super(flow);
+ constructor(flow, fn, description, opt_stackOptions, opt_isUserTask) {
+ super(flow, SKIP_LOG);
getUid(this);
/** @type {function(): (T|!ManagedPromise<T>)} */
@@ -2676,6 +2795,9 @@ class Task extends Deferred {
/** @type {TaskQueue} */
this.queue = null;
+ /** @private @const {boolean} */
+ this.userTask_ = !!opt_isUserTask;
+
/**
* Whether this task is considered block. A blocked task may be registered
* in a task queue, but will be dropped if it is still blocked when it
@@ -2889,7 +3011,7 @@ class TaskQueue extends events.EventEmitter {
}
// Now that all of the remaining tasks have been silently cancelled (e.g. no
- // exisitng callbacks on those tasks will fire), clear the silence bit on
+ // existing callbacks on those tasks will fire), clear the silence bit on
// the cancellation error. This ensures additional callbacks registered in
// the future will actually execute.
cancellation.silent_ = false;
@@ -2935,7 +3057,7 @@ class TaskQueue extends events.EventEmitter {
this.subQ_.once('end', () => { // On task completion.
this.subQ_ = null;
- this.pending_ && this.pending_.task.fulfill(result);
+ this.pending_ && this.pending_.task.resolve(result);
});
this.subQ_.once('error', e => { // On task failure.
@@ -3068,7 +3190,7 @@ class TaskQueue extends events.EventEmitter {
}
return task;
}
-};
+}
@@ -3214,7 +3336,7 @@ function consume(generatorFn, opt_self, ...var_args) {
function pump(fn, opt_arg) {
if (ret instanceof ManagedPromise && !isPending(ret)) {
- return; // Defererd was cancelled; silently abort.
+ return; // Deferred was cancelled; silently abort.
}
try {
@@ -3246,6 +3368,7 @@ module.exports = {
MultipleUnhandledRejectionError: MultipleUnhandledRejectionError,
Thenable: Thenable,
Promise: ManagedPromise,
+ Resolver: Resolver,
Scheduler: Scheduler,
all: all,
asap: asap,
@@ -3254,6 +3377,7 @@ module.exports = {
consume: consume,
controlFlow: controlFlow,
createFlow: createFlow,
+ createPromise: createPromise,
defer: defer,
delayed: delayed,
filter: filter,
@@ -3275,7 +3399,7 @@ module.exports = {
* The promise manager is currently enabled by default, but may be disabled
* by setting the environment variable `SELENIUM_PROMISE_MANAGER=0` or by
* setting this property to false. Setting this property will always take
- * precedence ove the use of the environment variable.
+ * precedence over the use of the environment variable.
*
* @return {boolean} Whether the promise manager is enabled.
* @see <https://github.com/SeleniumHQ/selenium/issues/2969>
diff --git a/node_modules/selenium-webdriver/lib/symbols.js b/node_modules/selenium-webdriver/lib/symbols.js
index d5c62504e..6c7cd1d9d 100644
--- a/node_modules/selenium-webdriver/lib/symbols.js
+++ b/node_modules/selenium-webdriver/lib/symbols.js
@@ -30,7 +30,7 @@ module.exports = {
* available, the serialize method will return a promise that will be resolved
* with the serialized form.
*
- * Note that the described method is analgous to objects that define a
+ * Note that the described method is analogous to objects that define a
* `toJSON()` method, except the serialized result may be a promise, or
* another object with a promised property.
*/
diff --git a/node_modules/selenium-webdriver/lib/test/index.js b/node_modules/selenium-webdriver/lib/test/index.js
index ba34ddab4..b3275ccbb 100644
--- a/node_modules/selenium-webdriver/lib/test/index.js
+++ b/node_modules/selenium-webdriver/lib/test/index.js
@@ -24,6 +24,7 @@ var build = require('./build'),
webdriver = require('../../'),
flow = webdriver.promise.controlFlow(),
firefox = require('../../firefox'),
+ logging = require('../../lib/logging'),
safari = require('../../safari'),
remote = require('../../remote'),
testing = require('../../testing'),
@@ -56,6 +57,11 @@ var noMarionette = /^0|false$/i.test(process.env['SELENIUM_GECKODRIVER']);
var startServer = !!serverJar && !remoteUrl;
var nativeRun = !serverJar && !remoteUrl;
+if (/^1|true$/i.test(process.env['SELENIUM_VERBOSE'])) {
+ logging.installConsoleHandler();
+ logging.getLogger('webdriver.http').setLevel(logging.Level.ALL);
+}
+
var browsersToTest = (function() {
var permitRemoteBrowsers = !!remoteUrl || !!serverJar;
var permitUnknownBrowsers = !nativeRun;
diff --git a/node_modules/selenium-webdriver/lib/until.js b/node_modules/selenium-webdriver/lib/until.js
index 0cc6f5ea3..b0e68b88b 100644
--- a/node_modules/selenium-webdriver/lib/until.js
+++ b/node_modules/selenium-webdriver/lib/until.js
@@ -72,7 +72,7 @@ const webdriver = require('./webdriver'),
exports.ableToSwitchToFrame = function ableToSwitchToFrame(frame) {
var condition;
if (typeof frame === 'number' || frame instanceof webdriver.WebElement) {
- condition = attemptToSwitchFrames;
+ condition = driver => attemptToSwitchFrames(driver, frame);
} else {
condition = function(driver) {
let locator = /** @type {!(By|Function)} */(frame);
diff --git a/node_modules/selenium-webdriver/lib/webdriver.js b/node_modules/selenium-webdriver/lib/webdriver.js
index 081d77bda..c8d04e82a 100644
--- a/node_modules/selenium-webdriver/lib/webdriver.js
+++ b/node_modules/selenium-webdriver/lib/webdriver.js
@@ -457,12 +457,12 @@ class IWebDriver {
* while evaluating the condition, they will be allowed to propagate. In the
* event a condition returns a {@link promise.Promise promise}, the polling
* loop will wait for it to be resolved and use the resolved value for whether
- * the condition has been satisified. Note the resolution time for a promise
+ * the condition has been satisfied. Note the resolution time for a promise
* is factored into whether a wait has timed out.
*
* Note, if the provided condition is a {@link WebElementCondition}, then
* the wait will return a {@link WebElementPromise} that will resolve to the
- * element that satisified the condition.
+ * element that satisfied the condition.
*
* _Example:_ waiting up to 10 seconds for an element to be present on the
* page.
@@ -779,7 +779,7 @@ class WebDriver {
'WebDriver.createSession()');
if (typeof opt_onQuit === 'function') {
session = session.catch(err => {
- return Promise.resolve(opt_onQuit.call(void 0)).then(_ => {throw err});
+ return Promise.resolve(opt_onQuit.call(void 0)).then(_ => {throw err;});
});
}
const ctor = opt_ctor || WebDriver;
@@ -850,7 +850,7 @@ class WebDriver {
new command.Command(command.Name.QUIT),
'WebDriver.quit()');
// Delete our session ID when the quit command finishes; this will allow us
- // to throw an error when attemnpting to use a driver post-quit.
+ // to throw an error when attempting to use a driver post-quit.
return /** @type {!promise.Thenable} */(promise.finally(result, () => {
this.session_ = this.flow_.promise((_, reject) => {
reject(new error.NoSuchSessionError(
@@ -1181,7 +1181,7 @@ class Navigation {
/**
* Provides methods for managing browser and driver state.
*
- * This class should never be instantiated directly. Insead, obtain an instance
+ * This class should never be instantiated directly. Instead, obtain an instance
* with {@linkplain WebDriver#manage() webdriver.manage()}.
*/
class Options {
@@ -1427,7 +1427,7 @@ Options.Cookie.prototype.expiry;
/**
* An interface for managing timeout behavior for WebDriver instances.
*
- * This class should never be instantiated directly. Insead, obtain an instance
+ * This class should never be instantiated directly. Instead, obtain an instance
* with
*
* webdriver.manage().timeouts()
@@ -2009,7 +2009,7 @@ class WebElement {
* this instance.
*
* Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is
- * processed in the keysequence, that key state is toggled until one of the
+ * processed in the key sequence, that key state is toggled until one of the
* following occurs:
*
* - The modifier key is encountered again in the sequence. At this point the
@@ -2028,13 +2028,13 @@ class WebElement {
* Key.chord(Key.CONTROL, "a"),
* "now text is");
*
- * - The end of the keysequence is encountered. When there are no more keys
+ * - The end of the key sequence is encountered. When there are no more keys
* to type, all depressed modifier keys are released (with accompanying
* keyup events).
*
* If this element is a file input ({@code <input type="file">}), the
* specified key sequence should specify the path to the file to attach to
- * the element. This is analgous to the user clicking "Browse..." and entering
+ * the element. This is analogous to the user clicking "Browse..." and entering
* the path into the file select dialog.
*
* var form = driver.findElement(By.css('form'));
@@ -2050,7 +2050,7 @@ class WebElement {
*
* __Note:__ On browsers where native keyboard events are not supported
* (e.g. Firefox on OS X), key events will be synthesized. Special
- * punctionation keys will be synthesized according to a standard QWERTY en-us
+ * punctuation keys will be synthesized according to a standard QWERTY en-us
* keyboard layout.
*
* @param {...(number|string|!IThenable<(number|string)>)} var_args The
@@ -2214,7 +2214,7 @@ class WebElement {
/**
* Schedules a command to query whether the DOM element represented by this
- * instance is enabled, as dicted by the {@code disabled} attribute.
+ * instance is enabled, as dictated by the {@code disabled} attribute.
* @return {!promise.Thenable<boolean>} A promise that will be
* resolved with whether this element is currently enabled.
*/
@@ -2327,7 +2327,7 @@ class WebElementPromise extends WebElement {
if (promise.CancellableThenable.isImplementation(el)) {
/** @type {!promise.CancellableThenable} */(el).cancel(opt_reason);
}
- }
+ };
/** @override */
this.then = el.then.bind(el);
diff --git a/node_modules/selenium-webdriver/opera.js b/node_modules/selenium-webdriver/opera.js
index cc84f2af5..5107bae4e 100644
--- a/node_modules/selenium-webdriver/opera.js
+++ b/node_modules/selenium-webdriver/opera.js
@@ -62,7 +62,7 @@
* var options = new opera.Options();
* // configure browser options ...
*
- * var driver = new opera.Driver(options, service);
+ * var driver = opera.Driver.createSession(options, service);
*
* Users should only instantiate the {@link Driver} class directly when they
* need a custom driver service configuration (as shown above). For normal
diff --git a/node_modules/selenium-webdriver/package.json b/node_modules/selenium-webdriver/package.json
index 5c3935833..dfb557bf4 100644
--- a/node_modules/selenium-webdriver/package.json
+++ b/node_modules/selenium-webdriver/package.json
@@ -1,6 +1,6 @@
{
"name": "selenium-webdriver",
- "version": "3.0.1",
+ "version": "3.3.0",
"description": "The official WebDriver JavaScript bindings from the Selenium project",
"license": "Apache-2.0",
"keywords": [
diff --git a/node_modules/selenium-webdriver/remote/index.js b/node_modules/selenium-webdriver/remote/index.js
index 87dee7e8d..cc0b66462 100644
--- a/node_modules/selenium-webdriver/remote/index.js
+++ b/node_modules/selenium-webdriver/remote/index.js
@@ -492,7 +492,12 @@ class SeleniumServer extends DriverService {
return jvmArgs.concat('-jar', jar, '-port', port).concat(args);
});
- super('java', {
+ let java = 'java';
+ if (process.env['JAVA_HOME']) {
+ java = path.join(process.env['JAVA_HOME'], 'bin/java');
+ }
+
+ super(java, {
loopback: options.loopback,
port: port,
args: args,
diff --git a/node_modules/selenium-webdriver/safari.js b/node_modules/selenium-webdriver/safari.js
index 97d512bc7..5a57387c1 100644
--- a/node_modules/selenium-webdriver/safari.js
+++ b/node_modules/selenium-webdriver/safari.js
@@ -68,7 +68,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
const OPTIONS_CAPABILITY_KEY = 'safari.options';
-
+const TECHNOLOGY_PREVIEW_OPTIONS_KEY = 'technologyPreview';
/**
* Configuration options specific to the {@link Driver SafariDriver}.
@@ -89,16 +89,17 @@ class Options {
* Extracts the SafariDriver specific options from the given capabilities
* object.
* @param {!Capabilities} capabilities The capabilities object.
- * @return {!Options} The ChromeDriver options.
+ * @return {!Options} The SafariDriver options.
*/
static fromCapabilities(capabilities) {
var options = new Options();
-
var o = capabilities.get(OPTIONS_CAPABILITY_KEY);
+
if (o instanceof Options) {
options = o;
} else if (o) {
options.setCleanSession(o.cleanSession);
+ options.setTechnologyPreview(o[TECHNOLOGY_PREVIEW_OPTIONS_KEY]);
}
if (capabilities.has(Capability.PROXY)) {
@@ -149,6 +150,22 @@ class Options {
}
/**
+ * Instruct the SafariDriver to use the Safari Technology Preview if true.
+ * Otherwise, use the release version of Safari. Defaults to using the release version of Safari.
+ *
+ * @param {boolean} useTechnologyPreview
+ * @return {!Options} A self reference.
+ */
+ setTechnologyPreview(useTechnologyPreview) {
+ if (!this.options_) {
+ this.options_ = {};
+ }
+
+ this.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY] = !!useTechnologyPreview;
+ return this;
+ }
+
+ /**
* Converts this options instance to a {@link Capabilities} object.
* @param {Capabilities=} opt_capabilities The capabilities to
* merge these options into, if any.
@@ -179,6 +196,23 @@ class Options {
}
}
+/**
+ * @param {(Options|Object<string, *>)=} o The options object
+ * @return {boolean}
+ */
+function useTechnologyPreview(o) {
+ if (o instanceof Options) {
+ return !!(o.options_ && o.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY]);
+ }
+
+ if (o && typeof o === 'object') {
+ return !!o[TECHNOLOGY_PREVIEW_OPTIONS_KEY];
+ }
+
+ return false;
+}
+
+const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver';
/**
* A WebDriver client for Safari. This class should never be instantiated
@@ -200,14 +234,19 @@ class Driver extends webdriver.WebDriver {
* @return {!Driver} A new driver instance.
*/
static createSession(opt_config, opt_flow) {
- let caps;
+ let caps, exe;
+
if (opt_config instanceof Options) {
caps = opt_config.toCapabilities();
} else {
- caps = opt_config || Capabilities.safari()
+ caps = opt_config || Capabilities.safari();
+ }
+
+ if (useTechnologyPreview(caps.get(OPTIONS_CAPABILITY_KEY))) {
+ exe = SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE;
}
- let service = new ServiceBuilder().build();
+ let service = new ServiceBuilder(exe).build();
let executor = new http.Executor(
service.start().then(url => new http.HttpClient(url)));
diff --git a/node_modules/selenium-webdriver/test/firefox/firefox_test.js b/node_modules/selenium-webdriver/test/firefox/firefox_test.js
index 485964f91..dbf9910fa 100644
--- a/node_modules/selenium-webdriver/test/firefox/firefox_test.js
+++ b/node_modules/selenium-webdriver/test/firefox/firefox_test.js
@@ -26,6 +26,8 @@ var firefox = require('../../firefox'),
Context = require('../../firefox').Context,
error = require('../..').error;
+var {consume} = require('../../lib/promise');
+
var JETPACK_EXTENSION = path.join(__dirname,
'../../lib/test/data/firefox/jetpack-sample.xpi');
@@ -53,9 +55,7 @@ test.suite(function(env) {
* skipped if dev cannot be found on the current system.
*/
function runWithFirefoxDev(options, testFn) {
- let binary = new firefox.Binary();
- binary.useDevEdition();
- return binary.locate().then(exe => {
+ return firefox.Channel.AURORA.locate().then(exe => {
options.setBinary(exe);
driver = env.builder()
.setFirefoxOptions(options)
@@ -67,21 +67,33 @@ test.suite(function(env) {
});
}
- test.it('can start Firefox with custom preferences', function*() {
- var profile = new firefox.Profile();
- profile.setPreference('general.useragent.override', 'foo;bar');
+ describe('can start Firefox with custom preferences', function() {
+ function runTest(opt_dir) {
+ return consume(function*() {
+ let profile = new firefox.Profile(opt_dir);
+ profile.setPreference('general.useragent.override', 'foo;bar');
+
+ let options = new firefox.Options().setProfile(profile);
+
+ driver = env.builder().
+ setFirefoxOptions(options).
+ build();
- var options = new firefox.Options().setProfile(profile);
+ yield driver.get('data:text/html,<html><div>content</div></html>');
- driver = env.builder().
- setFirefoxOptions(options).
- build();
+ var userAgent = yield driver.executeScript(
+ 'return window.navigator.userAgent');
+ assert(userAgent).equalTo('foo;bar');
+ });
+ }
- yield driver.get('data:text/html,<html><div>content</div></html>');
+ test.it('profile created from scratch', function() {
+ return runTest();
+ });
- var userAgent = yield driver.executeScript(
- 'return window.navigator.userAgent');
- assert(userAgent).equalTo('foo;bar');
+ test.it('profile created from template', function() {
+ return io.tmpDir().then(runTest);
+ });
});
test.it('can start Firefox with a jetpack extension', function() {
diff --git a/node_modules/selenium-webdriver/test/lib/http_test.js b/node_modules/selenium-webdriver/test/lib/http_test.js
index 1c6c073ad..2dd27869d 100644
--- a/node_modules/selenium-webdriver/test/lib/http_test.js
+++ b/node_modules/selenium-webdriver/test/lib/http_test.js
@@ -325,6 +325,37 @@ describe('http', function() {
assert.ok(executor.w3c, 'should never downgrade');
});
});
+
+ it('handles legacy new session failures', function() {
+ let rawResponse = {
+ status: error.ErrorCode.NO_SUCH_ELEMENT,
+ value: {message: 'hi'}
+ };
+
+ send.returns(Promise.resolve(
+ new http.Response(500, {}, JSON.stringify(rawResponse))));
+
+ return executor.execute(command)
+ .then(() => assert.fail('should have failed'),
+ e => {
+ assert.ok(e instanceof error.NoSuchElementError);
+ assert.equal(e.message, 'hi');
+ });
+ });
+
+ it('handles w3c new session failures', function() {
+ let rawResponse = {error: 'no such element', message: 'oops'};
+
+ send.returns(Promise.resolve(
+ new http.Response(500, {}, JSON.stringify(rawResponse))));
+
+ return executor.execute(command)
+ .then(() => assert.fail('should have failed'),
+ e => {
+ assert.ok(e instanceof error.NoSuchElementError);
+ assert.equal(e.message, 'oops');
+ });
+ });
});
describe('extracts Session from DESCRIBE_SESSION response', function() {
diff --git a/node_modules/selenium-webdriver/test/lib/promise_test.js b/node_modules/selenium-webdriver/test/lib/promise_test.js
index 96d2ccc22..8da1cd89e 100644
--- a/node_modules/selenium-webdriver/test/lib/promise_test.js
+++ b/node_modules/selenium-webdriver/test/lib/promise_test.js
@@ -301,6 +301,25 @@ describe('promise', function() {
});
promiseManagerSuite(() => {
+ describe('fulfilled', function() {
+ it('returns input value if it is already a valid promise', function() {
+ let p = promise.createPromise(function() {});
+ let r = promise.fulfilled(p);
+ assert.strictEqual(p, r);
+ });
+
+ it('creates a new promise fulfilled with input', function() {
+ return promise.fulfilled(1234).then(v => assert.equal(1234, v));
+ });
+
+ it('can convert thenables to valid promise', function() {
+ let thenable = {then: function(cb) {cb(1234)}};
+ let p = promise.fulfilled(thenable);
+ assert.notStrictEqual(thenable, p);
+ return p.then(v => assert.equal(1234, v));
+ });
+ });
+
describe('when', function() {
it('ReturnsAResolvedPromiseIfGivenANonPromiseValue', function() {
var ret = promise.when('abc');
diff --git a/node_modules/selenium-webdriver/test/lib/until_test.js b/node_modules/selenium-webdriver/test/lib/until_test.js
index 31b2b32ad..3226a467a 100644
--- a/node_modules/selenium-webdriver/test/lib/until_test.js
+++ b/node_modules/selenium-webdriver/test/lib/until_test.js
@@ -70,39 +70,54 @@ describe('until', function() {
.then(fail, (e2) => assert.strictEqual(e2, e));
});
+ const ELEMENT_ID = 'some-element-id';
+ const ELEMENT_INDEX = 1234;
+
+ function onSwitchFrame(expectedId) {
+ if (typeof expectedId === 'string') {
+ expectedId = WebElement.buildId(expectedId);
+ } else {
+ assert.equal(typeof expectedId, 'number', 'must be string or number');
+ }
+ return cmd => {
+ assert.deepEqual(
+ cmd.getParameter('id'), expectedId, 'frame ID not specified');
+ return true;
+ };
+ }
+
it('byIndex', function() {
- executor.on(CommandName.SWITCH_TO_FRAME, () => true);
- return driver.wait(until.ableToSwitchToFrame(0), 100);
+ executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_INDEX));
+ return driver.wait(until.ableToSwitchToFrame(ELEMENT_INDEX), 100);
});
it('byWebElement', function() {
- executor.on(CommandName.SWITCH_TO_FRAME, () => true);
- var el = new webdriver.WebElement(driver, {ELEMENT: 1234});
+ executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID));
+
+ var el = new webdriver.WebElement(driver, ELEMENT_ID);
return driver.wait(until.ableToSwitchToFrame(el), 100);
});
it('byWebElementPromise', function() {
- executor.on(CommandName.SWITCH_TO_FRAME, () => true);
+ executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID));
var el = new webdriver.WebElementPromise(driver,
- Promise.resolve(new webdriver.WebElement(driver, {ELEMENT: 1234})));
+ Promise.resolve(new webdriver.WebElement(driver, ELEMENT_ID)));
return driver.wait(until.ableToSwitchToFrame(el), 100);
});
it('byLocator', function() {
- executor.on(CommandName.FIND_ELEMENTS, () => [WebElement.buildId(1234)]);
- executor.on(CommandName.SWITCH_TO_FRAME, () => true);
+ executor.on(CommandName.FIND_ELEMENTS, () => [WebElement.buildId(ELEMENT_ID)]);
+ executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID));
return driver.wait(until.ableToSwitchToFrame(By.id('foo')), 100);
});
it('byLocator_elementNotInitiallyFound', function() {
- var foundResponses = [[], [], [WebElement.buildId(1234)]];
+ let foundResponses = [[], [], [WebElement.buildId(ELEMENT_ID)]];
executor.on(CommandName.FIND_ELEMENTS, () => foundResponses.shift());
- executor.on(CommandName.SWITCH_TO_FRAME, () => true);
+ executor.on(CommandName.SWITCH_TO_FRAME, onSwitchFrame(ELEMENT_ID));
return driver.wait(until.ableToSwitchToFrame(By.id('foo')), 2000)
- .then(function() {
- assert.equal(foundResponses.length, 0);
- });
+ .then(() => assert.deepEqual(foundResponses, []));
});
it('timesOutIfNeverAbletoSwitchFrames', function() {
diff --git a/node_modules/selenium-webdriver/testing/index.js b/node_modules/selenium-webdriver/testing/index.js
index 5bb82d15f..88763c7d5 100644
--- a/node_modules/selenium-webdriver/testing/index.js
+++ b/node_modules/selenium-webdriver/testing/index.js
@@ -41,16 +41,14 @@
* The provided wrappers leverage the {@link webdriver.promise.ControlFlow}
* to simplify writing asynchronous tests:
*
- * var By = require('selenium-webdriver').By,
- * until = require('selenium-webdriver').until,
- * firefox = require('selenium-webdriver/firefox'),
- * test = require('selenium-webdriver/testing');
+ * var {Builder, By, until} = require('selenium-webdriver');
+ * var test = require('selenium-webdriver/testing');
*
* test.describe('Google Search', function() {
* var driver;
*
* test.before(function() {
- * driver = new firefox.Driver();
+ * driver = new Builder().forBrowser('firefox').build();
* });
*
* test.after(function() {
@@ -293,6 +291,19 @@ exports.describe = function(name, opt_fn) {
/**
+ * An alias for {@link #describe()} that marks the suite as exclusive,
+ * suppressing all other test suites.
+ * @param {string} name The suite name.
+ * @param {function()=} opt_fn The suite function, or `undefined` to define
+ * a pending test suite.
+ */
+exports.describe.only = function(name, opt_fn) {
+ let desc = getMochaGlobal('describe');
+ return opt_fn ? desc.only(name, opt_fn) : desc.only(name);
+};
+
+
+/**
* Defines a suppressed test suite.
* @param {string} name The suite name.
* @param {function()=} opt_fn The suite function, or `undefined` to define