Deployed the page to Github Pages.

This commit is contained in:
Batuhan Berk Başoğlu 2024-11-03 21:30:09 -05:00
parent 1d79754e93
commit 2c89899458
Signed by: batuhan-basoglu
SSH key fingerprint: SHA256:kEsnuHX+qbwhxSAXPUQ4ox535wFHu/hIRaa53FzxRpo
62797 changed files with 6551425 additions and 15279 deletions

2
node_modules/selenium-webdriver/.npmignore generated vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules/

851
node_modules/selenium-webdriver/CHANGES.md generated vendored Normal file
View file

@ -0,0 +1,851 @@
## v3.6.0
### Bug Fixes
* The Capabilities factory methods should only specify the name of the browser.
* Protect against the remote end sometimes not returning a list to findElements
commands.
* Properly reset state in `remote.DriverService#kill()`
* The firefox module will no longer apply the preferences required by the legacy
FirefoxDriver. These preferences were only required when using the legacy
driver, support for which was dropped in v3.5.0.
### API Changes
* Added new methods to `selenium-webdriver/firefox.Options`:
- addArguments()
- headless()
- windowSize()
* Deprecated `selenium-webdriver/firefox/binary.Binary`
* Removed `selenium-webdriver/firefox.Options#useGeckoDriver()`
* Removed the unused `selenium-webdriver/firefox/profile.decode()`
* Removed methods from `selenium-webdriver/firefox/profile.Profile` that had
no effect since support for the legacy FirefoxDriver was dropped in 3.5.0:
- setNativeEventsEnabled
- nativeEventsEnabled
- getPort
- setPort
* Removed `selenium-webdriver/firefox.ServiceBuilder#setFirefoxBinary()`; custom
binaries should be configured through the `firefox.Options` class.
* Removed `selenium-webdriver/firefox.Capability`. These hold overs from the
legacy FirefoxDriver are no longer supported.
### Changes for W3C WebDriver Spec Compliance
* Deprecated `error.ElementNotVisibleError` in favor of the more generic
`error.ElementNotInteractableError`.
* Support the `httpOnly` option when adding a cookie.
## v3.5.0
### Notice
Native support for Firefox 45 (ESR) has been removed. Users will have to connect
to a remote Selenium server that supports Firefox 45.
### Changes
* Removed native support for Firefox 46 and older.
- The `SELENIUM_MARIONETTE` enviornment variable no longer has an effect.
- `selenium-webdriver/firefox.Capability.MARIONETTE` is deprecated.
- `selenium-webdriver/firefox.Options#useGeckoDriver()` is deprecated and now a no-op.
* `firefox.Options` will no longer discard the `"moz:firefoxOptions"` set in
user provided capabilities (via `Builder.withCapabilities({})`). When both
are used, the settings in `firefox.Options` will be applied _last_.
* Added `chrome.Options#headless()` and `chrome.Options#windowSize()`, which
may be used to start Chrome in headless mode (requires Chrome 59+) and to set
the initial window size, respectively.
### Changes for W3C WebDriver Spec Compliance
* Added `error.WebDriverError#remoteStacktrace` to capture the stacktrace
reported by a remote WebDriver endpoint (if any).
* Fixed `WebElement#sendKeys` to send text as a string instead of an array of
strings.
## v3.4.0
### Notice
This release requires [geckodriver 0.15.0](https://github.com/mozilla/geckodriver/releases/tag/v0.15.0) or newer.
### API Changes
* Added `Options#getTimeouts()` for retrieving the currently configured session
timeouts (i.e. implicit wait). This method will only work with W3C compatible
WebDriver implementations.
* Deprecated the `Timeouts` class in favor of `Options#setTimeouts()`, which
supports setting multiple timeouts at once.
* Added support for emulating different network conditions (e.g., offline, 2G, WiFi) on Chrome.
### Changes for W3C WebDriver Spec Compliance
* Fixed W3C response parsing, which expects response data to always be a JSON
object with a `value` key.
* Added W3C endpoints for interacting with various types of
[user prompts](https://w3c.github.io/webdriver/webdriver-spec.html#user-prompts).
* Added W3C endpoints for remotely executing scripts.
* Added W3C endpoints to get current window handle and all windows handles.
## 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
- Deprecated `promise.fulfilled(value)`, use `promise.Promise#resolve(value)`
- Deprecated `promise.rejected(reason)`, use `promise.Promise#reject(reason)`
* When a `wait()` condition times out, the returned promise will now be
rejected with an `error.TimeoutError` instead of a generic `Error` object.
* `WebDriver#wait()` will now throw a TypeError if an invalid wait condition is
provided.
* Properly catch unhandled promise rejections with an action sequence (only
impacts when the promise manager is disabled).
## v3.0.0
* (__NOTICE__) The minimum supported version of Node is now 6.9.0 LTS
* Removed support for the SafariDriver browser extension. This has been
replaced by Apple's safaridriver, which is included wtih Safari 10
(available on OS X El Capitan and macOS Sierra).
To use Safari 9 or older, users will have to use an older version of Selenium.
* geckodriver v0.11.0 or newer is now required for Firefox.
* Fixed potential reference errors in `selenium-webdriver/testing` when users
create a cycle with mocha by running with mocha's `--hook` flag.
* Fixed `WebDriver.switchTo().activeElement()` to use the correct HTTP method
for compatibility with the W3C spec.
* Update the `selenium-webdriver/firefox` module to use geckodriver's
"moz:firefoxOptions" dictionary for Firefox-specific configuration values.
* Extending the `selenium-webdriver/testing` module to support tests defined
using generator functions.
* The promise manager can be disabled by setting an enviornment variable:
`SELENIUM_PROMISE_MANAGER=0`. This is part of a larger plan to remove the
promise manager, as documented at
<https://github.com/SeleniumHQ/selenium/issues/2969>
* When communicating with a W3C-compliant remote end, use the atoms library for
the `WebElement.getAttribute()` and `WebElement.isDisplayed()` commands. This
behavior is consistent with the java, .net, python, and ruby clients.
### API Changes
* Removed `safari.Options#useLegacyDriver()`
* Reduced the API on `promise.Thenable` for compatibility with native promises:
- Removed `#isPending()`
- Removed `#cancel()`
- Removed `#finally()`
* Changed all subclasses of `webdriver.WebDriver` to overload the static
function `WebDriver.createSession()` instead of doing work in the
constructor. All constructors now inherit the base class' function signature.
Users are still encouraged to use the `Builder` class instead of creating
drivers directly.
* `Builder#build()` now returns a "thenable" WebDriver instance, allowing users
to immediately schedule commands (as before), or issue them through standard
promise callbacks. This is the same pattern already employed for WebElements.
* Removed `Builder#buildAsync()` as it was redundant with the new semantics of
`build()`.
## v3.0.0-beta-3
* Fixed a bug where the promise manager would silently drop callbacks after
recovering from an unhandled promise rejection.
* Added the `firefox.ServiceBuilder` class, which may be used to customize the
geckodriver used for `firefox.Driver` instances.
* Added support for Safari 10 safaridriver. safaridriver may be disabled
via tha API, `safari.Options#useLegacyDriver`, to use the safari
extension driver.
* Updated the `lib/proxy` module to support configuring a SOCKS proxy.
* For the `promise.ControlFlow`, fire the "uncaughtException" event in a new
turn of the JS event loop. As a result of this change, any errors thrown by
an event listener will propagate to the global error handler. Previously,
this event was fired with in the context of a (native) promise callback,
causing errors to be silently suppressed in the promise chain.
### API Changes
* Added `remote.DriverService.Builder` as a base class for configuring
DriverService instances that run in a child-process. The
`chrome.ServiceBuilder`, `edge.ServiceBuilder`, and `opera.ServiceBuilder`
classes now all extend this base class with browser-specific options.
* For each of the ServiceBuilder clases, renamed `usingPort` and
`withEnvironment` to `setPort` and `setEnvironment`, respectively.
* Renamed `chrome.ServiceBuilder#setUrlBasePath` to `#setPath`
* Changed the signature of the `firefox.Driver` from `(config, flow, executor)`
to `(config, executor, flow)`.
* Exposed the `Condition` and `WebElementCondition` classes from the top-level
`selenium-webdriver` module (these were previously only available from
`lib/webdriver`).
### Changes for W3C WebDriver Spec Compliance
* Updated command mappings for [getting](https://w3c.github.io/webdriver/webdriver-spec.html#get-window-position)
and [setting](https://w3c.github.io/webdriver/webdriver-spec.html#set-window-position)
the window position.
## v3.0.0-beta-2
### API Changes
* Moved the `builder.Builder` class into the main module (`selenium-webdriver`).
* Removed the `builder` module.
* Fix `webdriver.WebDriver#setFileDetector` when driving Chrome or Firefox on a
remote machine.
## v3.0.0-beta-1
* Allow users to set the agent used for HTTP connections through
`builder.Builder#usingHttpAgent()`
* Added new wait conditions: `until.urlIs()`, `until.urlContains()`,
`until.urlMatches()`
* Added work around for [GeckoDriver bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1274924)
raising a type conversion error
* Internal cleanup replacing uses of managed promises with native promises
* Removed the mandatory use of Firefox Dev Edition, when using Marionette driver
* Fixed timeouts' URL
* Properly send HTTP requests when using a WebDriver server proxy
* Properly configure proxies when using the geckodriver
* `http.Executor` now accepts a promised client. The `builder.Builder` class
will now use this instead of a `command.DeferredExecutor` when creating
WebDriver instances.
* For Chrome and Firefox, the `builder.Builder` class will always return an
instanceof `chrome.Driver` and `firefox.Driver`, respectively, even when
configured to use a remote server (from `builder.Builder#usingServer(url)`,
`SELENIUM_REMOTE_URL`, etc).
### API Changes
* `promise.Deferred` is no longer a thenable object.
* `Options#addCookie()` now takes a record object instead of 7 individual
parameters. A TypeError will be thrown if addCookie() is called with invalid
arguments.
* When adding cookies, the desired expiry must be provided as a Date or in
_seconds_ since epoch. When retrieving cookies, the expiration is always
returned in seconds.
* Renamed `firefox.Options#useMarionette` to `firefox.Options#useGeckoDriver`
* Removed deprecated modules:
- `selenium-webdriver/error` (use `selenium-webdriver/lib/error`,\
or the `error` property exported by `selenium-webdriver`)
- `selenium-webdriver/executors` — this was not previously deprecated, but
is no longer used.
* Removed deprecated types:
- `command.DeferredExecutor` — this was not previously deprecated, but is no
longer used. It can be trivially implemented by clients should it be
needed.
- `error.InvalidSessionIdError` (use `error.NoSuchSessionError`)
- `executors.DeferredExecutor`
- `until.Condition` (use `webdriver.Condition`)
- `until.WebElementCondition` (use `webdriver.WebElementCondition`)
- `webdriver.UnhandledAlertError` (use `error.UnexpectedAlertOpenError`)
* Removed deprecated functions:
- `Deferred#cancel()`
- `Deferred#catch()`
- `Deferred#finally()`
- `Deferred#isPending()`
- `Deferred#then()`
- `Promise#thenCatch()`
- `Promise#thenFinally()`
- `WebDriver#isElementPresent()`
- `WebElement#getInnerHtml()`
- `WebElement#getOuterHtml()`
- `WebElement#getRawId()`
- `WebElement#isElementPresent()`
* Removed deprecated properties:
- `WebDriverError#code`
## v2.53.2
* Changed `io.exists()` to return a rejected promise if the input path is not
a string
* Deprecated `Promise#thenFinally()` - use `Promise#finally()`. The thenFinally
shim added to the promise module in v2.53.0 will be removed in v3.0
Sorry for the churn!
* FIXED: capabilities serialization now properly handles undefined vs.
false-like values.
* FIXED: properly handle responses from the remote end in
`WebDriver.attachToSession`
## v2.53.1
* FIXED: for consistency with the other language bindings, `remote.FileDetector`
will ignore paths that refer to a directory.
## v2.53.0
### Change Summary
* Added preliminary support for Marionette, Mozilla's WebDriver implementation
for Firefox. Marionette may be enabled via the API,
`firefox.Options#useMarionette`, or by setting the `SELENIUM_MARIONETTE`
environment variable.
* Moved all logic for parsing and interpreting responses from the remote end
into the individual `command.Executor` implementations.
* For consistency with the other Selenium language bindings,
`WebDriver#isElementPresent()` and `WebElement#isElementPresent()` have
been deprecated. These methods will be removed in v3.0. Use the findElements
command to test for the presence of an element:
driver.findElements(By.css('.foo')).then(found => !!found.length);
* Added support for W3C-spec compliant servers.
* For consistent naming, deprecating `error.InvalidSessionIdError` in favor of
`error.NoSuchSessionError`.
* Moved the `error` module to `lib/error` so all core modules are co-located.
The top-level `error` module will be removed in v3.0.
* Moved `until.Condition` and `until.WebElementCondition` to the webdriver
module to break a circular dependency.
* Added support for setting the username and password in basic auth pop-up
dialogs (currently IE only).
* Deprecated `WebElement#getInnerHtml()` and `WebEleemnt#getOuterHtml()`
* Deprecated `Promise#thenCatch()` - use `Promise#catch()` instead
* Deprecated `Promise#thenFinally()` - use `promise.thenFinally()` instead
* FIXED: `io.findInPath()` will no longer match against directories that have
the same basename as the target file.
* FIXED: `phantomjs.Driver` now takes a third argument that defines the path to
a log file to use for the phantomjs executable's output. This may be quickly
set at runtime with the `SELENIUM_PHANTOMJS_LOG` environment variable.
### Changes for W3C WebDriver Spec Compliance
* Changed `element.sendKeys(...)` to send the key sequence as an array where
each element defines a single key. The legacy wire protocol permits arrays
where each element is a string of arbitrary length. This change is solely
at the protocol level and should have no user-visible effect.
## v2.52.0
### Notice
Starting with v2.52.0, each release of selenium-webdriver will support the
latest _minor_ LTS and stable Node releases. All releases between the LTS and
stable release will have best effort support. Further details are available in
the selenium-webdriver package README.
### Change Summary
* Add support for Microsoft's Edge web browser
* Added `webdriver.Builder#buildAsync()`, which returns a promise that will be
fulfilled with the newly created WebDriver instance once the associated
browser has been full initialized. This is purely a convenient alternative
to the existing build() method as the WebDriver class will always defer
commands until it has a fully created browser.
* Added `firefox.Profile#setHost()` which may be used to set the host that
the FirefoxDriver's server listens for commands on. The server uses
"localhost" by default.
* Added `promise.Promise#catch()` for API compatibility with native Promises.
`promise.Promise#thenCatch()` is not yet deprecated, but it simply
delegates to `catch`.
* Changed some `io` operations to use native promises.
* Changed `command.Executor#execute()` and `HttpClient#send()` to return
promises instead of using callback passing.
* Replaced the `Serializable` class with an internal, Symbol-defined method.
* Changed the `Capabilities` class to extend the native `Map` type.
* Changed the `Capabilities.has(key)` to only test if a capability has been set
(Map semantics). To check whether the value is true, use `get(key)`.
* Deprecated `executors.DeferredExecutor` in favor of
`lib/command.DeferredExecutor`.
* API documentation is no longer distributed with the npm package, but remains
available at <http://seleniumhq.github.io/selenium/docs/api/javascript/>
* Rewrote the `error` module to export an Error subtype for each type of error
defined in the [W3C WebDriver spec](https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors).
* Changed the `http.Request` and `http.Response` classes to store headers in
maps instead of object literals.
* Updated `ws` dependency to version `1.0.1`.
* Removed fluent predicates "is" and "not" from the experimental
`testing/assert` module.
* Wait conditions that locate an element, or that wait on an element's state,
will return a WebElementPromise.
* Lots of internal clean-up to break selenium-webdriver's long standing
dependency on Google's Closure library.
### Changes for W3C WebDriver Spec Compliance
* Updated the `By` locators that are not in the W3C spec to delegated to using
CSS selectors: `By.className`, `By.id`, `By.name`, and `By.tagName`.
## v2.49-51
* _Releases skipped to stay in sync with the rest of the Selenium project_
## v2.48.2
* Added `WebElement#takeScreenshot()`.
* More adjustments to promise callback tracking.
## v2.48.1
* FIXED: Adjusted how the control flow tracks promise callbacks to avoid a
potential deadlock.
## v2.48.0
* Node v0.12.x users must run with --harmony. _This is the last release that
will support v0.12.x_
* FIXED: (Promise/A+ compliance) When a promise is rejected with a thenable,
the promise adopts the thenable as its rejection reason instead of waiting
for it to settle. The previous (incorrect) behavior was hidden by bugs in
the `promises-aplus-tests` compliance test suite that were fixed in version
`2.1.1`.
* FIXED: the `webdriver.promise.ControlFlow` now has a consistent execution
order for tasks/callbacks scheduled in different turns of the JS event loop.
Refer to the `webdriver.promise` documentation for more details.
* FIXED: do not drop user auth from the WebDriver server URL.
* FIXED: a single `firefox.Binary` instance may be used to configure and
launch multiple FirefoxDriver sessions.
var binary = new firefox.Binary();
var options = new firefox.Options().setBinary(binary);
var builder = new Builder().setFirefoxOptions(options);
var driver1 = builder.build();
var driver2 = builder.build();
* FIXED: zip files created for transfer to a remote WebDriver server are no
longer compressed. If the zip contained a file that was already compressed,
the server would return an "invalid code lengths set" error.
* FIXED: Surfaced the `loopback` option to `remote/SeleniumServer`. When set,
the server will be accessed using the current host's loopback address.
## v2.47.0
### Notice
This is the last release for `selenium-webdriver` that will support ES5.
Subsequent releases will depend on ES6 features that are enabled by
[default](https://nodejs.org/en/docs/es6/) in Node v4.0.0. Node v0.12.x will
continue to be supported, but will require setting the `--harmony` flag.
### Change Summary
* Add support for [Node v4.0.0](https://nodejs.org/en/blog/release/v4.0.0/)
* Updated `ws` dependency from `0.7.1` to `0.8.0`
* Bumped the minimum supported version of Node from `0.10.x` to `0.12.x`. This
is in accordance with the Node support policy established in `v2.45.0`.
## v2.46.1
* Fixed internal module loading on Windows.
* Fixed error message format on timeouts for `until.elementLocated()`
and `until.elementsLocated()`.
## v2.46.0
* Exposed a new logging API via the `webdriver.logging` module. For usage, see
`example/logging.js`.
* Added support for using a proxy server for WebDriver commands.
See `Builder#usingWebDriverProxy()` for more info.
* Removed deprecated functions:
* Capabilities#toJSON()
* UnhandledAlertError#getAlert()
* chrome.createDriver()
* phantomjs.createDriver()
* promise.ControlFlow#annotateError()
* promise.ControlFlow#await()
* promise.ControlFlow#clearHistory()
* promise.ControlFlow#getHistory()
* Removed deprecated enum values: `ErrorCode.NO_MODAL_DIALOG_OPEN` and
`ErrorCode.MODAL_DIALOG_OPENED`. Use `ErrorCode.NO_SUCH_ALERT` and
`ErrorCode.UNEXPECTED_ALERT_OPEN`, respectively.
* FIXED: The `promise.ControlFlow` will maintain state for promise chains
generated in a loop.
* FIXED: Correct serialize target elements used in an action sequence.
* FIXED: `promise.ControlFlow#wait()` now has consistent semantics for an
omitted or 0-timeout: it will wait indefinitely.
* FIXED: `remote.DriverService#start()` will now fail if the child process dies
while waiting for the server to start accepting requests. Previously, start
would continue to poll the server address until the timeout expired.
* FIXED: Skip launching Firefox with the `-silent` flag to preheat the profile.
Starting with Firefox 38, this would cause the browser to crash. This step,
which was first introduced for Selenium's java client back with Firefox 2,
no longer appears to be required.
* FIXED: 8564: `firefox.Driver#quit()` will wait for the Firefox process to
terminate before deleting the temporary webdriver profile. This eliminates a
race condition where Firefox would write profile data during shutdown,
causing the `rm -rf` operation on the profile directory to fail.
## v2.45.1
* FIXED: 8548: Task callbacks are once again dropped if the task was cancelled
due to a previously uncaught error within the frame.
* FIXED: 8496: Extended the `chrome.Options` API to cover all configuration
options (e.g. mobile emulation and performance logging) documented on the
ChromeDriver [project site](https://sites.google.com/a/chromium.org/chromedriver/capabilities).
## v2.45.0
### Important Policy Change
Starting with the 2.45.0 release, selenium-webdriver will support the last
two stable minor releases for Node. For 2.45.0, this means Selenium will
support Node 0.10.x and 0.12.x. Support for the intermediate, un-stable release
(0.11.x) is "best-effort". This policy will be re-evaluated once Node has a
major version release (i.e. 1.0.0).
### Change Summary
* Added native browser support for Internet Explorer, Opera 26+, and Safari
* With the release of [Node 0.12.0](http://blog.nodejs.org/2015/02/06/node-v0-12-0-stable/)
(finally!), the minimum supported version of Node is now `0.10.x`.
* The `promise` module is now [Promises/A+](https://promisesaplus.com/)
compliant. The biggest compliance change is that promise callbacks are now
invoked in a future turn of the JS event loop. For example:
var promise = require('selenium-webdriver').promise;
console.log('start');
promise.fulfilled().then(function() {
console.log('middle');
});
console.log('end');
// Output in selenium-webdriver@2.44.0
// start
// middle
// end
//
// Output in selenium-webdriver@2.45.0
// start
// end
// middle
The `promise.ControlFlow` class has been updated to track the asynchronous
breaks required by Promises/A+, so there are no changes to task execution
order.
* Updated how errors are annotated on failures. When a task fails, the
stacktrace from when that task was scheduled is appended to the rejection
reason with a `From: ` prefix (if it is an Error object). For example:
var driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('http://www.google.com/ncr');
driver.call(function() {
driver.wait(function() {
return driver.isElementPresent(webdriver.By.id('not-there'));
}, 2000, 'element not found');
});
This code will fail an error like:
Error: element not found
Wait timed out after 2002ms
at <stack trace>
From: Task: element not found
at <stack trace>
From: Task: WebDriver.call(function)
at <stack trace>
* Changed the format of strings returned by `promise.ControlFlow#getSchedule`.
This function now accepts a boolean to control whether the returned string
should include the stacktraces for when each task was scheduled.
* Deprecating `promise.ControlFlow#getHistory`,
`promise.ControlFlow#clearHistory`, and `promise.ControlFlow#annotateError`.
These functions were all intended for internal use and are no longer
necessary, so they have been made no-ops.
* `WebDriver.wait()` may now be used to wait for a promise to resolve, with
an optional timeout. Refer to the API documentation for more information.
* Added support for copying files to a remote Selenium via `sendKeys` to test
file uploads. Refer to the API documentation for more information. Sample
usage included in `test/upload_test.js`
* Expanded the interactions API to include touch actions.
See `WebDriver.touchActions()`.
* FIXED: 8380: `firefox.Driver` will delete its temporary profile on `quit`.
* FIXED: 8306: Stack overflow in promise callbacks eliminated.
* FIXED: 8221: Added support for defining custom command mappings. Includes
support for PhantomJS's `executePhantomJS` (requires PhantomJS 1.9.7 or
GhostDriver 1.1.0).
* FIXED: 8128: When the FirefoxDriver marshals an object to the page for
`executeScript`, it defines additional properties (required by the driver's
implementation). These properties will no longer be enumerable and should
be omitted (i.e. they won't show up in JSON.stringify output).
* FIXED: 8094: The control flow will no longer deadlock when a task returns
a promise that depends on the completion of sub-tasks.
## v2.44.0
* Added the `until` module, which defines common explicit wait conditions.
Sample usage:
var firefox = require('selenium-webdriver/firefox'),
until = require('selenium-webdriver/until');
var driver = new firefox.Driver();
driver.get('http://www.google.com/ncr');
driver.wait(until.titleIs('Google Search'), 1000);
* FIXED: 8000: `Builder.forBrowser()` now accepts an empty string since some
WebDriver implementations ignore the value. A value must still be specified,
however, since it is a required field in WebDriver's wire protocol.
* FIXED: 7994: The `stacktrace` module will not modify stack traces if the
initial parse fails (e.g. the user defined `Error.prepareStackTrace`)
* FIXED: 5855: Added a module (`until`) that defines several common conditions
for use with explicit waits. See updated examples for usage.
## v2.43.5
* FIXED: 7905: `Builder.usingServer(url)` once again returns `this` for
chaining.
## v2.43.2-4
* No changes; version bumps while attempting to work around an issue with
publishing to npm (a version string may only be used once).
## v2.43.1
* Fixed an issue with flakiness when setting up the Firefox profile that could
prevent the driver from initializing properly.
## v2.43.0
* Added native support for Firefox - the Java Selenium server is no longer
required.
* Added support for generator functions to `ControlFlow#execute` and
`ControlFlow#wait`. For more information, see documentation on
`webdriver.promise.consume`. Requires harmony support (run with
`node --harmony-generators` in `v0.11.x`).
* Various improvements to the `Builder` API. Notably, the `build()` function
will no longer default to attempting to use a server at
`http://localhost:4444/wd/hub` if it cannot start a browser directly -
you must specify the WebDriver server with `usingServer(url)`. You can
also set the target browser and WebDriver server through a pair of
environment variables. See the documentation on the `Builder` constructor
for more information.
* For consistency with the other language bindings, added browser specific
classes that can be used to start a browser without the builder.
var webdriver = require('selenium-webdriver')
chrome = require('selenium-webdriver/chrome');
// The following are equivalent.
var driver1 = new webdriver.Builder().forBrowser('chrome').build();
var driver2 = new chrome.Driver();
* Promise A+ compliance: a promise may no longer resolve to itself.
* For consistency with other language bindings, deprecated
`UnhandledAlertError#getAlert` and added `#getAlertText`.
`getAlert` will be removed in `2.45.0`.
* FIXED: 7641: Deprecated `ErrorCode.NO_MODAL_DIALOG_OPEN` and
`ErrorCode.MODAL_DIALOG_OPENED` in favor of the new
`ErrorCode.NO_SUCH_ALERT` and `ErrorCode.UNEXPECTED_ALERT_OPEN`,
respectively.
* FIXED: 7563: Mocha integration no longer disables timeouts. Default Mocha
timeouts apply (2000 ms) and may be changed using `this.timeout(ms)`.
* FIXED: 7470: Make it easier to create WebDriver instances in custom flows for
parallel execution.
## v2.42.1
* FIXED: 7465: Fixed `net.getLoopbackAddress` on Windows
* FIXED: 7277: Support `done` callback in Mocha's BDD interface
* FIXED: 7156: `Promise#thenFinally` should not suppress original error
## v2.42.0
* Removed deprecated functions `Promise#addCallback()`,
`Promise#addCallbacks()`, `Promise#addErrback()`, and `Promise#addBoth()`.
* Fail with a more descriptive error if the server returns a malformed redirect
* FIXED: 7300: Connect to ChromeDriver using the loopback address since
ChromeDriver 2.10.267517 binds to localhost by default.
* FIXED: 7339: Preserve wrapped test function's string representation for
Mocha's BDD interface.
## v2.41.0
* FIXED: 7138: export logging API from webdriver module.
* FIXED: 7105: beforeEach/it/afterEach properly bind `this` for Mocha tests.
## v2.40.0
* API documentation is now included in the docs directory.
* Added utility functions for working with an array of promises:
`promise.all`, `promise.map`, and `promise.filter`
* Introduced `Promise#thenCatch()` and `Promise#thenFinally()`.
* Deprecated `Promise#addCallback()`, `Promise#addCallbacks()`,
`Promise#addErrback()`, and `Promise#addBoth()`.
* Removed deprecated function `webdriver.WebDriver#getCapability`.
* FIXED: 6826: Added support for custom locators.
## v2.39.0
* Version bump to stay in sync with the Selenium project.
## v2.38.1
* FIXED: 6686: Changed `webdriver.promise.Deferred#cancel()` to silently no-op
if the deferred has already been resolved.
## v2.38.0
* When a promise is rejected, always annotate the stacktrace with the parent
flow state so users can identify the source of an error.
* Updated tests to reflect features not working correctly in the SafariDriver
(cookie management and proxy support; see issues 5051, 5212, and 5503)
* FIXED: 6284: For mouse moves, correctly omit the x/y offsets if not
specified as a function argument (instead of passing (0,0)).
* FIXED: 6471: Updated documentation on `webdriver.WebElement#getAttribute`
* FIXED: 6612: On Unix, use the default IANA ephemeral port range if unable to
retrieve the current system's port range.
* FIXED: 6617: Avoid triggering the node debugger when initializing the
stacktrace module.
* FIXED: 6627: Safely rebuild chrome.Options from a partial JSON spec.
## v2.37.0
* FIXED: 6346: The remote.SeleniumServer class now accepts JVM arguments using
the `jvmArgs` option.
## v2.36.0
* _Release skipped to stay in sync with main Selenium project._
## v2.35.2
* FIXED: 6200: Pass arguments to the Selenium server instead of to the JVM.
## v2.35.1
* FIXED: 6090: Changed example scripts to use chromedriver.
## v2.35.0
* Version bump to stay in sync with the Selenium project.
## v2.34.1
* FIXED: 6079: The parent process should not wait for spawn driver service
processes (chromedriver, phantomjs, etc.)
## v2.34.0
* Added the `selenium-webdriver/testing/assert` module. This module
simplifies writing assertions against promised values (see
example in module documentation).
* Added the `webdriver.Capabilities` class.
* Added native support for the ChromeDriver. When using the `Builder`,
requesting chrome without specifying a remote server URL will default to
the native ChromeDriver implementation. The
[ChromeDriver server](https://code.google.com/p/chromedriver/downloads/list)
must be downloaded separately.
// Will start ChromeDriver locally.
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
// Will start ChromeDriver using the remote server.
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
usingServer('http://server:1234/wd/hub').
build();
* Added support for configuring proxies through the builder. For examples, see
`selenium-webdriver/test/proxy_test`.
* Added native support for PhantomJS.
* Changed signature of `SeleniumServer` to `SeleniumServer(jar, options)`.
* Tests are now included in the npm published package. See `README.md` for
execution instructions
* Removed the deprecated `webdriver.Deferred#resolve` and
`webdriver.promise.resolved` functions.
* Removed the ability to connect to an existing session from the Builder. This
feature is intended for use with the browser-based client.
## v2.33.0
* Added support for WebDriver's logging API
* FIXED: 5511: Added webdriver.manage().timeouts().pageLoadTimeout(ms)
## v2.32.1
* FIXED: 5541: Added missing return statement for windows in
`portprober.findFreePort()`
## v2.32.0
* Added the `selenium-webdriver/testing` package, which provides a basic
framework for writing tests using Mocha. See
`selenium-webdriver/example/google_search_test.js` for usage.
* For Promises/A+ compatibility, backing out the change in 2.30.0 that ensured
rejections were always Error objects. Rejection reasons are now left as is.
* Removed deprecated functions originally scheduled for removal in 2.31.0
* promise.Application.getInstance()
* promise.ControlFlow#schedule()
* promise.ControlFlow#scheduleTimeout()
* promise.ControlFlow#scheduleWait()
* Renamed some functions for consistency with Promises/A+ terminology. The
original functions have been deprecated and will be removed in 2.34.0:
* promise.resolved() -> promise.fulfilled()
* promise.Deferred#resolve() -> promise.Deferred#fulfill()
* FIXED: remote.SeleniumServer#stop now shuts down within the active control
flow, allowing scripts to finish. Use #kill to shutdown immediately.
* FIXED: 5321: cookie deletion commands
## v2.31.0
* Added an example script.
* Added a class for controlling the standalone Selenium server (server
available separately)
* Added a portprober for finding free ports
* FIXED: WebElements now belong to the same flow as their parent driver.
## v2.30.0
* Ensures promise rejections are always Error values.
* Version bump to keep in sync with the Selenium project.
## v2.29.1
* Fixed a bug that could lead to an infinite loop.
* Added a README.md
## v2.29.0
* Initial release for npm:
npm install selenium-webdriver

202
node_modules/selenium-webdriver/LICENSE generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016 Software Freedom Conservancy (SFC)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2
node_modules/selenium-webdriver/NOTICE generated vendored Normal file
View file

@ -0,0 +1,2 @@
Copyright 2011-2017 Software Freedom Conservancy
Copyright 2004-2011 Selenium committers

226
node_modules/selenium-webdriver/README.md generated vendored Normal file
View file

@ -0,0 +1,226 @@
# selenium-webdriver
Selenium is a browser automation library. Most often used for testing
web-applications, Selenium may be used for any task that requires automating
interaction with the browser.
## Installation
Selenium may be installed via npm with
npm install selenium-webdriver
You will need to download additional components to work with each of the major
browsers. The drivers for Chrome, Firefox, PhantomJS, Opera, and
Microsoft's IE and Edge web browsers are all standalone executables that should
be placed on your system [PATH]. Apple's safaridriver is shipped with
Safari 10 for OS X El Capitan and macOS Sierra. You will need to enable Remote
Automation in the Develop menu of Safari 10 before testing.
| Browser | Component |
| ----------------- | ---------------------------------- |
| Chrome | [chromedriver(.exe)][chrome] |
| Internet Explorer | [IEDriverServer.exe][release] |
| Edge | [MicrosoftWebDriver.msi][edge] |
| Firefox | [geckodriver(.exe)][geckodriver] |
| PhantomJS | [phantomjs(.exe)][phantomjs] |
| Opera | [operadriver(.exe)][opera] |
| Safari | [safaridriver] |
## Usage
The sample below and others are included in the `example` directory. You may
also find the tests for selenium-webdriver informative.
const {Builder, By, Key, until} = require('selenium-webdriver');
let driver = new Builder()
.forBrowser('firefox')
.build();
driver.get('http://www.google.com/ncr');
driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
driver.wait(until.titleIs('webdriver - Google Search'), 1000);
driver.quit();
### Using the Builder API
The `Builder` class is your one-stop shop for configuring new WebDriver
instances. Rather than clutter your code with branches for the various browsers,
the builder lets you set all options in one flow. When you call
`Builder#build()`, all options irrelevant to the selected browser are dropped:
var webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome'),
firefox = require('selenium-webdriver/firefox');
var driver = new webdriver.Builder()
.forBrowser('firefox')
.setChromeOptions(/* ... */)
.setFirefoxOptions(/* ... */)
.build();
Why would you want to configure options irrelevant to the target browser? The
`Builder`'s API defines your _default_ configuration. You can change the target
browser at runtime through the `SELENIUM_BROWSER` environment variable. For
example, the `example/google_search.js` script is configured to run against
Firefox. You can run the example against other browsers just by changing the
runtime environment
# cd node_modules/selenium-webdriver
node example/google_search
SELENIUM_BROWSER=chrome node example/google_search
SELENIUM_BROWSER=safari node example/google_search
### The Standalone Selenium Server
The standalone Selenium Server acts as a proxy between your script and the
browser-specific drivers. The server may be used when running locally, but it's
not recommend as it introduces an extra hop for each request and will slow
things down. The server is required, however, to use a browser on a remote host
(most browser drivers, like the IEDriverServer, do not accept remote
connections).
To use the Selenium Server, you will need to install the
[JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and
download the latest server from [Selenium][release]. Once downloaded, run the
server with
java -jar selenium-server-standalone-2.45.0.jar
You may configure your tests to run against a remote server through the Builder
API:
var driver = new webdriver.Builder()
.forBrowser('firefox')
.usingServer('http://localhost:4444/wd/hub')
.build();
Or change the Builder's configuration at runtime with the `SELENIUM_REMOTE_URL`
environment variable:
SELENIUM_REMOTE_URL="http://localhost:4444/wd/hub" node script.js
You can experiment with these options using the `example/google_search.js`
script provided with `selenium-webdriver`.
## Documentation
API documentation is available online from the [Selenium project][api].
Additional resources include
- the #selenium channel on freenode IRC
- the [selenium-users@googlegroups.com][users] list
- [SeleniumHQ](http://www.seleniumhq.org/docs/) documentation
## Contributing
Contributions are accepted either through [GitHub][gh] pull requests or patches
via the [Selenium issue tracker][issues]. You must sign our
[Contributor License Agreement][cla] before your changes will be accepted.
## Node Support Policy
Each version of selenium-webdriver will support the latest _semver-minor_
version of the [LTS] and stable Node releases. All _semver-major_ &
_semver-minor_ versions between the LTS and stable release will have "best
effort" support. Following a Selenium release, any _semver-minor_ Node releases
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 v6.9.5 and v7.5.0,
respectively. Then a Selenium release would have the following support levels:
| Version | Support |
| ------- | ------------- |
| <= 6.8 | _unsupported_ |
| 6.9 | supported |
| 7.0-4 | best effort |
| 7.5 | supported |
| >= 7.5 | best effort |
| v.Next | _unsupported_ |
### Support Level Definitions
- _supported:_ A selenium-webdriver release will be API compatible with the
platform API, without the use of runtime flags.
- _best effort:_ Bugs will be investigated as time permits. API compatibility is
only guaranteed where required by a _supported_ release. This effectively
means the adoption of new JS features, such as ES2015 modules, will depend
on what is supported in Node's LTS.
- _unsupported:_ Bug submissions will be closed as will-not-fix and API
compatibility is not guaranteed.
### Projected Support Schedule
If Node releases a new [LTS] each October and a new major version every 6
months, the support window for selenium-webdriver will be roughly:
| Date | LTS | Stable |
| --------- | ---: | -----: |
| (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
Please report any issues using the [Selenium issue tracker][issues]. When using
the issue tracker
- __Do__ include a detailed description of the problem.
- __Do__ include a link to a [gist](http://gist.github.com/) with any
interesting stack traces/logs (you may also attach these directly to the bug
report).
- __Do__ include a [reduced test case][reduction]. Reporting "unable to find
element on the page" is _not_ a valid report - there's nothing for us to
look into. Expect your bug report to be closed if you do not provide enough
information for us to investigate.
- __Do not__ use the issue tracker to submit basic help requests. All help
inquiries should be directed to the [user forum][users] or #selenium IRC
channel.
- __Do not__ post empty "I see this too" or "Any updates?" comments. These
provide no additional information and clutter the log.
- __Do not__ report regressions on closed bugs as they are not actively
monitored for updates (especially bugs that are >6 months old). Please open a
new issue and reference the original bug in your report.
## License
Licensed to the Software Freedom Conservancy (SFC) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The SFC licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
[LTS]: https://github.com/nodejs/LTS
[PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
[api]: http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/
[cla]: http://goo.gl/qC50R
[chrome]: http://chromedriver.storage.googleapis.com/index.html
[gh]: https://github.com/SeleniumHQ/selenium/
[issues]: https://github.com/SeleniumHQ/selenium/issues
[opera]: https://github.com/operasoftware/operachromiumdriver/releases
[phantomjs]: http://phantomjs.org/
[edge]: http://go.microsoft.com/fwlink/?LinkId=619687
[geckodriver]: https://github.com/mozilla/geckodriver/releases/
[reduction]: http://www.webkit.org/quality/reduction.html
[release]: http://selenium-release.storage.googleapis.com/index.html
[users]: https://groups.google.com/forum/#!forum/selenium-users
[safaridriver]: https://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28

829
node_modules/selenium-webdriver/chrome.js generated vendored Normal file
View file

@ -0,0 +1,829 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Defines a {@linkplain Driver WebDriver} client for the Chrome
* web browser. Before using this module, you must download the latest
* [ChromeDriver release] and ensure it can be found on your system [PATH].
*
* There are three primary classes exported by this module:
*
* 1. {@linkplain ServiceBuilder}: configures the
* {@link selenium-webdriver/remote.DriverService remote.DriverService}
* that manages the [ChromeDriver] child process.
*
* 2. {@linkplain Options}: defines configuration options for each new Chrome
* session, such as which {@linkplain Options#setProxy proxy} to use,
* what {@linkplain Options#addExtensions extensions} to install, or
* what {@linkplain Options#addArguments command-line switches} to use when
* starting the browser.
*
* 3. {@linkplain Driver}: the WebDriver client; each new instance will control
* a unique browser session with a clean user profile (unless otherwise
* configured through the {@link Options} class).
*
* __Headless Chrome__ <a id="headless"></a>
*
* To start Chrome in headless mode, simply call
* {@linkplain Options#headless Options.headless()}. Note, starting in headless
* mode currently also disables GPU acceleration.
*
* let chrome = require('selenium-webdriver/chrome');
* let {Builder} = require('selenium-webdriver');
*
* let driver = new Builder()
* .forBrowser('chrome')
* .setChromeOptions(new chrome.Options().headless())
* .build();
*
* __Customizing the ChromeDriver Server__ <a id="custom-server"></a>
*
* By default, every Chrome session will use a single driver service, which is
* started the first time a {@link Driver} instance is created and terminated
* when this process exits. The default service will inherit its environment
* from the current process and direct all output to /dev/null. You may obtain
* a handle to this default service using
* {@link #getDefaultService getDefaultService()} and change its configuration
* with {@link #setDefaultService setDefaultService()}.
*
* You may also create a {@link Driver} with its own driver service. This is
* useful if you need to capture the server's log output for a specific session:
*
* let chrome = require('selenium-webdriver/chrome');
*
* let service = new chrome.ServiceBuilder()
* .loggingTo('/my/log/file.txt')
* .enableVerboseLogging()
* .build();
*
* let options = new chrome.Options();
* // configure browser options ...
*
* 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
* operation, users should start Chrome using the
* {@link selenium-webdriver.Builder}.
*
* __Working with Android__ <a id="android"></a>
*
* The [ChromeDriver][android] supports running tests on the Chrome browser as
* well as [WebView apps][webview] starting in Android 4.4 (KitKat). In order to
* work with Android, you must first start the adb
*
* adb start-server
*
* By default, adb will start on port 5037. You may change this port, but this
* will require configuring a [custom server](#custom-server) that will connect
* to adb on the {@linkplain ServiceBuilder#setAdbPort correct port}:
*
* let service = new chrome.ServiceBuilder()
* .setAdbPort(1234)
* build();
* // etc.
*
* The ChromeDriver may be configured to launch Chrome on Android using
* {@link Options#androidChrome()}:
*
* let driver = new Builder()
* .forBrowser('chrome')
* .setChromeOptions(new chrome.Options().androidChrome())
* .build();
*
* Alternatively, you can configure the ChromeDriver to launch an app with a
* Chrome-WebView by setting the {@linkplain Options#androidActivity
* androidActivity} option:
*
* let driver = new Builder()
* .forBrowser('chrome')
* .setChromeOptions(new chrome.Options()
* .androidPackage('com.example')
* .androidActivity('com.example.Activity'))
* .build();
*
* [Refer to the ChromeDriver site] for more information on using the
* [ChromeDriver with Android][android].
*
* [ChromeDriver]: https://sites.google.com/a/chromium.org/chromedriver/
* [ChromeDriver release]: http://chromedriver.storage.googleapis.com/index.html
* [PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
* [android]: https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android
* [webview]: https://developer.chrome.com/multidevice/webview/overview
*/
'use strict';
const fs = require('fs');
const util = require('util');
const http = require('./http');
const io = require('./io');
const {Capabilities, Capability} = require('./lib/capabilities');
const command = require('./lib/command');
const logging = require('./lib/logging');
const promise = require('./lib/promise');
const Symbols = require('./lib/symbols');
const webdriver = require('./lib/webdriver');
const portprober = require('./net/portprober');
const remote = require('./remote');
/**
* Name of the ChromeDriver executable.
* @type {string}
* @const
*/
const CHROMEDRIVER_EXE =
process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver';
/**
* Custom command names supported by ChromeDriver.
* @enum {string}
*/
const Command = {
LAUNCH_APP: 'launchApp',
GET_NETWORK_CONDITIONS: 'getNetworkConditions',
SET_NETWORK_CONDITIONS: 'setNetworkConditions'
};
/**
* Creates a command executor with support for ChromeDriver's custom commands.
* @param {!Promise<string>} url The server's URL.
* @return {!command.Executor} The new command executor.
*/
function createExecutor(url) {
let client = url.then(url => new http.HttpClient(url));
let executor = new http.Executor(client);
configureExecutor(executor);
return executor;
}
/**
* Configures the given executor with Chrome-specific commands.
* @param {!http.Executor} executor the executor to configure.
*/
function configureExecutor(executor) {
executor.defineCommand(
Command.LAUNCH_APP,
'POST',
'/session/:sessionId/chromium/launch_app');
executor.defineCommand(
Command.GET_NETWORK_CONDITIONS,
'GET',
'/session/:sessionId/chromium/network_conditions');
executor.defineCommand(
Command.SET_NETWORK_CONDITIONS,
'POST',
'/session/:sessionId/chromium/network_conditions');
}
/**
* Creates {@link selenium-webdriver/remote.DriverService} instances that manage
* a [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/)
* server in a child process.
*/
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
* the builder will attempt to locate the chromedriver on the current
* PATH.
* @throws {Error} If provided executable does not exist, or the chromedriver
* cannot be found on the PATH.
*/
constructor(opt_exe) {
let exe = opt_exe || io.findInPath(CHROMEDRIVER_EXE, true);
if (!exe) {
throw Error(
'The ChromeDriver could not be found on the current PATH. Please ' +
'download the latest version of the ChromeDriver from ' +
'http://chromedriver.storage.googleapis.com/index.html and ensure ' +
'it can be found on your PATH.');
}
super(exe);
this.setLoopback(true); // Required
}
/**
* Sets which port adb is listening to. _The ChromeDriver will connect to adb
* if an {@linkplain Options#androidPackage Android session} is requested, but
* adb **must** be started beforehand._
*
* @param {number} port Which port adb is running on.
* @return {!ServiceBuilder} A self reference.
*/
setAdbPort(port) {
return this.addArguments('--adb-port=' + port);
}
/**
* Sets the path of the log file the driver should log to. If a log file is
* not specified, the driver will log to stderr.
* @param {string} path Path of the log file to use.
* @return {!ServiceBuilder} A self reference.
*/
loggingTo(path) {
return this.addArguments('--log-path=' + path);
}
/**
* Enables verbose logging.
* @return {!ServiceBuilder} A self reference.
*/
enableVerboseLogging() {
return this.addArguments('--verbose');
}
/**
* Sets the number of threads the driver should use to manage HTTP requests.
* By default, the driver will use 4 threads.
* @param {number} n The number of threads to use.
* @return {!ServiceBuilder} A self reference.
*/
setNumHttpThreads(n) {
return this.addArguments('--http-threads=' + n);
}
/**
* @override
*/
setPath(path) {
super.setPath(path);
return this.addArguments('--url-base=' + path);
}
}
/** @type {remote.DriverService} */
let defaultService = null;
/**
* Sets the default service to use for new ChromeDriver instances.
* @param {!remote.DriverService} service The service to use.
* @throws {Error} If the default service is currently running.
*/
function setDefaultService(service) {
if (defaultService && defaultService.isRunning()) {
throw Error(
'The previously configured ChromeDriver service is still running. ' +
'You must shut it down before you may adjust its configuration.');
}
defaultService = service;
}
/**
* Returns the default ChromeDriver service. If such a service has not been
* configured, one will be constructed using the default configuration for
* a ChromeDriver executable found on the system PATH.
* @return {!remote.DriverService} The default ChromeDriver service.
*/
function getDefaultService() {
if (!defaultService) {
defaultService = new ServiceBuilder().build();
}
return defaultService;
}
const OPTIONS_CAPABILITY_KEY = 'chromeOptions';
/**
* Class for managing ChromeDriver specific options.
*/
class Options {
constructor() {
/** @private {!Object} */
this.options_ = {};
/** @private {!Array<(string|!Buffer)>} */
this.extensions_ = [];
/** @private {?logging.Preferences} */
this.logPrefs_ = null;
/** @private {?./lib/capabilities.ProxyConfig} */
this.proxy_ = null;
}
/**
* Extracts the ChromeDriver specific options from the given capabilities
* object.
* @param {!Capabilities} caps The capabilities object.
* @return {!Options} The ChromeDriver options.
*/
static fromCapabilities(caps) {
let options = new Options();
let o = caps.get(OPTIONS_CAPABILITY_KEY);
if (o instanceof Options) {
options = o;
} else if (o) {
options.
addArguments(o.args || []).
addExtensions(o.extensions || []).
detachDriver(o.detach).
excludeSwitches(o.excludeSwitches || []).
setChromeBinaryPath(o.binary).
setChromeLogFile(o.logPath).
setChromeMinidumpPath(o.minidumpPath).
setLocalState(o.localState).
setMobileEmulation(o.mobileEmulation).
setUserPreferences(o.prefs).
setPerfLoggingPrefs(o.perfLoggingPrefs);
}
if (caps.has(Capability.PROXY)) {
options.setProxy(caps.get(Capability.PROXY));
}
if (caps.has(Capability.LOGGING_PREFS)) {
options.setLoggingPrefs(
caps.get(Capability.LOGGING_PREFS));
}
return options;
}
/**
* Add additional command line arguments to use when launching the Chrome
* browser. Each argument may be specified with or without the "--" prefix
* (e.g. "--foo" and "foo"). Arguments with an associated value should be
* delimited by an "=": "foo=bar".
*
* @param {...(string|!Array<string>)} args The arguments to add.
* @return {!Options} A self reference.
*/
addArguments(...args) {
let newArgs = (this.options_.args || []).concat(...args);
if (newArgs.length) {
this.options_.args = newArgs;
}
return this;
}
/**
* Configures the chromedriver to start Chrome in headless mode.
*
* > __NOTE:__ Resizing the browser window in headless mode is only supported
* > in Chrome 60. Users are encouraged to set an initial window size with
* > the {@link #windowSize windowSize({width, height})} option.
*
* @return {!Options} A self reference.
*/
headless() {
// TODO(jleyba): Remove `disable-gpu` once head Chrome no longer requires
// that to be set.
return this.addArguments('headless', 'disable-gpu');
}
/**
* Sets the initial window size.
*
* @param {{width: number, height: number}} size The desired window size.
* @return {!Options} A self reference.
* @throws {TypeError} if width or height is unspecified, not a number, or
* less than or equal to 0.
*/
windowSize({width, height}) {
function checkArg(arg) {
if (typeof arg !== 'number' || arg <= 0) {
throw TypeError('Arguments must be {width, height} with numbers > 0');
}
}
checkArg(width);
checkArg(height);
return this.addArguments(`window-size=${width},${height}`);
}
/**
* List of Chrome command line switches to exclude that ChromeDriver by default
* passes when starting Chrome. Do not prefix switches with "--".
*
* @param {...(string|!Array<string>)} args The switches to exclude.
* @return {!Options} A self reference.
*/
excludeSwitches(...args) {
let switches = (this.options_.excludeSwitches || []).concat(...args);
if (switches.length) {
this.options_.excludeSwitches = switches;
}
return this;
}
/**
* Add additional extensions to install when launching Chrome. Each extension
* should be specified as the path to the packed CRX file, or a Buffer for an
* extension.
* @param {...(string|!Buffer|!Array<(string|!Buffer)>)} args The
* extensions to add.
* @return {!Options} A self reference.
*/
addExtensions(...args) {
this.extensions_ = this.extensions_.concat(...args);
return this;
}
/**
* Sets the path to the Chrome binary to use. On Mac OS X, this path should
* reference the actual Chrome executable, not just the application binary
* (e.g. "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").
*
* The binary path be absolute or relative to the chromedriver server
* executable, but it must exist on the machine that will launch Chrome.
*
* @param {string} path The path to the Chrome binary to use.
* @return {!Options} A self reference.
*/
setChromeBinaryPath(path) {
this.options_.binary = path;
return this;
}
/**
* Sets whether to leave the started Chrome browser running if the controlling
* ChromeDriver service is killed before {@link webdriver.WebDriver#quit()} is
* called.
* @param {boolean} detach Whether to leave the browser running if the
* chromedriver service is killed before the session.
* @return {!Options} A self reference.
*/
detachDriver(detach) {
this.options_.detach = detach;
return this;
}
/**
* Sets the user preferences for Chrome's user profile. See the "Preferences"
* file in Chrome's user data directory for examples.
* @param {!Object} prefs Dictionary of user preferences to use.
* @return {!Options} A self reference.
*/
setUserPreferences(prefs) {
this.options_.prefs = prefs;
return this;
}
/**
* Sets the logging preferences for the new session.
* @param {!logging.Preferences} prefs The logging preferences.
* @return {!Options} A self reference.
*/
setLoggingPrefs(prefs) {
this.logPrefs_ = prefs;
return this;
}
/**
* Sets the performance logging preferences. Options include:
*
* - `enableNetwork`: Whether or not to collect events from Network domain.
* - `enablePage`: Whether or not to collect events from Page domain.
* - `enableTimeline`: Whether or not to collect events from Timeline domain.
* Note: when tracing is enabled, Timeline domain is implicitly disabled,
* unless `enableTimeline` is explicitly set to true.
* - `tracingCategories`: A comma-separated string of Chrome tracing
* categories for which trace events should be collected. An unspecified
* or empty string disables tracing.
* - `bufferUsageReportingInterval`: The requested number of milliseconds
* between DevTools trace buffer usage events. For example, if 1000, then
* once per second, DevTools will report how full the trace buffer is. If
* a report indicates the buffer usage is 100%, a warning will be issued.
*
* @param {{enableNetwork: boolean,
* enablePage: boolean,
* enableTimeline: boolean,
* tracingCategories: string,
* bufferUsageReportingInterval: number}} prefs The performance
* logging preferences.
* @return {!Options} A self reference.
*/
setPerfLoggingPrefs(prefs) {
this.options_.perfLoggingPrefs = prefs;
return this;
}
/**
* Sets preferences for the "Local State" file in Chrome's user data
* directory.
* @param {!Object} state Dictionary of local state preferences.
* @return {!Options} A self reference.
*/
setLocalState(state) {
this.options_.localState = state;
return this;
}
/**
* Sets the name of the activity hosting a Chrome-based Android WebView. This
* option must be set to connect to an [Android WebView](
* https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android)
*
* @param {string} name The activity name.
* @return {!Options} A self reference.
*/
androidActivity(name) {
this.options_.androidActivity = name;
return this;
}
/**
* Sets the device serial number to connect to via ADB. If not specified, the
* ChromeDriver will select an unused device at random. An error will be
* returned if all devices already have active sessions.
*
* @param {string} serial The device serial number to connect to.
* @return {!Options} A self reference.
*/
androidDeviceSerial(serial) {
this.options_.androidDeviceSerial = serial;
return this;
}
/**
* Configures the ChromeDriver to launch Chrome on Android via adb. This
* function is shorthand for
* {@link #androidPackage options.androidPackage('com.android.chrome')}.
* @return {!Options} A self reference.
*/
androidChrome() {
return this.androidPackage('com.android.chrome');
}
/**
* Sets the package name of the Chrome or WebView app.
*
* @param {?string} pkg The package to connect to, or `null` to disable Android
* and switch back to using desktop Chrome.
* @return {!Options} A self reference.
*/
androidPackage(pkg) {
this.options_.androidPackage = pkg;
return this;
}
/**
* Sets the process name of the Activity hosting the WebView (as given by
* `ps`). If not specified, the process name is assumed to be the same as
* {@link #androidPackage}.
*
* @param {string} processName The main activity name.
* @return {!Options} A self reference.
*/
androidProcess(processName) {
this.options_.androidProcess = processName;
return this;
}
/**
* Sets whether to connect to an already-running instead of the specified
* {@linkplain #androidProcess app} instead of launching the app with a clean
* data directory.
*
* @param {boolean} useRunning Whether to connect to a running instance.
* @return {!Options} A self reference.
*/
androidUseRunningApp(useRunning) {
this.options_.androidUseRunningApp = useRunning;
return this;
}
/**
* Sets the path to Chrome's log file. This path should exist on the machine
* that will launch Chrome.
* @param {string} path Path to the log file to use.
* @return {!Options} A self reference.
*/
setChromeLogFile(path) {
this.options_.logPath = path;
return this;
}
/**
* Sets the directory to store Chrome minidumps in. This option is only
* supported when ChromeDriver is running on Linux.
* @param {string} path The directory path.
* @return {!Options} A self reference.
*/
setChromeMinidumpPath(path) {
this.options_.minidumpPath = path;
return this;
}
/**
* Configures Chrome to emulate a mobile device. For more information, refer
* to the ChromeDriver project page on [mobile emulation][em]. Configuration
* options include:
*
* - `deviceName`: The name of a pre-configured [emulated device][devem]
* - `width`: screen width, in pixels
* - `height`: screen height, in pixels
* - `pixelRatio`: screen pixel ratio
*
* __Example 1: Using a Pre-configured Device__
*
* let options = new chrome.Options().setMobileEmulation(
* {deviceName: 'Google Nexus 5'});
*
* let driver = chrome.Driver.createSession(options);
*
* __Example 2: Using Custom Screen Configuration__
*
* let options = new chrome.Options().setMobileEmulation({
* width: 360,
* height: 640,
* pixelRatio: 3.0
* });
*
* let driver = chrome.Driver.createSession(options);
*
*
* [em]: https://sites.google.com/a/chromium.org/chromedriver/mobile-emulation
* [devem]: https://developer.chrome.com/devtools/docs/device-mode
*
* @param {?({deviceName: string}|
* {width: number, height: number, pixelRatio: number})} config The
* mobile emulation configuration, or `null` to disable emulation.
* @return {!Options} A self reference.
*/
setMobileEmulation(config) {
this.options_.mobileEmulation = config;
return this;
}
/**
* Sets the proxy settings for the new session.
* @param {./lib/capabilities.ProxyConfig} proxy The proxy configuration to
* use.
* @return {!Options} A self reference.
*/
setProxy(proxy) {
this.proxy_ = proxy;
return this;
}
/**
* Converts this options instance to a {@link Capabilities} object.
* @param {Capabilities=} opt_capabilities The capabilities to merge
* these options into, if any.
* @return {!Capabilities} The capabilities.
*/
toCapabilities(opt_capabilities) {
let caps = opt_capabilities || Capabilities.chrome();
caps.
set(Capability.PROXY, this.proxy_).
set(Capability.LOGGING_PREFS, this.logPrefs_).
set(OPTIONS_CAPABILITY_KEY, this);
return caps;
}
/**
* Converts this instance to its JSON wire protocol representation. Note this
* function is an implementation not intended for general use.
* @return {!Object} The JSON wire protocol representation of this instance.
*/
[Symbols.serialize]() {
let json = {};
for (let key in this.options_) {
if (this.options_[key] != null) {
json[key] = this.options_[key];
}
}
if (this.extensions_.length) {
json.extensions = this.extensions_.map(function(extension) {
if (Buffer.isBuffer(extension)) {
return extension.toString('base64');
}
return io.read(/** @type {string} */(extension))
.then(buffer => buffer.toString('base64'));
});
}
return json;
}
}
/**
* Creates a new WebDriver client for Chrome.
*/
class Driver extends webdriver.WebDriver {
/**
* Creates a new session with the ChromeDriver.
*
* @param {(Capabilities|Options)=} opt_config The configuration options.
* @param {(remote.DriverService|http.Executor)=} opt_serviceExecutor Either
* a DriverService to use for the remote end, or a preconfigured executor
* for an externally managed endpoint. If neither is provided, the
* {@linkplain ##getDefaultService default service} will be used by
* default.
* @param {promise.ControlFlow=} opt_flow The control flow to use, or `null`
* to use the currently active flow.
* @return {!Driver} A new driver instance.
*/
static createSession(opt_config, opt_serviceExecutor, opt_flow) {
let executor;
if (opt_serviceExecutor instanceof http.Executor) {
executor = opt_serviceExecutor;
configureExecutor(executor);
} else {
let service = opt_serviceExecutor || getDefaultService();
executor = createExecutor(service.start());
}
let caps =
opt_config instanceof Options ? opt_config.toCapabilities() :
(opt_config || Capabilities.chrome());
return /** @type {!Driver} */(
super.createSession(executor, caps, opt_flow));
}
/**
* This function is a no-op as file detectors are not supported by this
* implementation.
* @override
*/
setFileDetector() {}
/**
* Schedules a command to launch Chrome App with given ID.
* @param {string} id ID of the App to launch.
* @return {!promise.Thenable<void>} A promise that will be resolved
* when app is launched.
*/
launchApp(id) {
return this.schedule(
new command.Command(Command.LAUNCH_APP).setParameter('id', id),
'Driver.launchApp()');
}
/**
* Schedules a command to get Chrome network emulation settings.
* @return {!promise.Thenable<T>} A promise that will be resolved
* when network emulation settings are retrievied.
*/
getNetworkConditions() {
return this.schedule(
new command.Command(Command.GET_NETWORK_CONDITIONS),
'Driver.getNetworkConditions()');
}
/**
* Schedules a command to set Chrome network emulation settings.
*
* __Sample Usage:__
*
* driver.setNetworkConditions({
* offline: false,
* latency: 5, // Additional latency (ms).
* download_throughput: 500 * 1024, // Maximal aggregated download throughput.
* upload_throughput: 500 * 1024 // Maximal aggregated upload throughput.
* });
*
* @param {Object} spec Defines the network conditions to set
* @return {!promise.Thenable<void>} A promise that will be resolved
* when network emulation settings are set.
*/
setNetworkConditions(spec) {
if (!spec || typeof spec !== 'object') {
throw TypeError('setNetworkConditions called with non-network-conditions parameter');
}
return this.schedule(
new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter('network_conditions', spec),
'Driver.setNetworkConditions(' + JSON.stringify(spec) + ')');
}
}
// PUBLIC API
exports.Driver = Driver;
exports.Options = Options;
exports.ServiceBuilder = ServiceBuilder;
exports.getDefaultService = getDefaultService;
exports.setDefaultService = setDefaultService;

301
node_modules/selenium-webdriver/edge.js generated vendored Normal file
View file

@ -0,0 +1,301 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Defines a {@linkplain Driver WebDriver} client for
* Microsoft's Edge web browser. Before using this module,
* you must download and install the latest
* [MicrosoftEdgeDriver](http://go.microsoft.com/fwlink/?LinkId=619687) server.
* Ensure that the MicrosoftEdgeDriver is on your
* [PATH](http://en.wikipedia.org/wiki/PATH_%28variable%29).
*
* There are three primary classes exported by this module:
*
* 1. {@linkplain ServiceBuilder}: configures the
* {@link ./remote.DriverService remote.DriverService}
* that manages the [MicrosoftEdgeDriver] child process.
*
* 2. {@linkplain Options}: defines configuration options for each new
* MicrosoftEdgeDriver session, such as which
* {@linkplain Options#setProxy proxy} to use when starting the browser.
*
* 3. {@linkplain Driver}: the WebDriver client; each new instance will control
* a unique browser session.
*
* __Customizing the MicrosoftEdgeDriver Server__ <a id="custom-server"></a>
*
* By default, every MicrosoftEdge session will use a single driver service,
* which is started the first time a {@link Driver} instance is created and
* terminated when this process exits. The default service will inherit its
* environment from the current process.
* You may obtain a handle to this default service using
* {@link #getDefaultService getDefaultService()} and change its configuration
* with {@link #setDefaultService setDefaultService()}.
*
* You may also create a {@link Driver} with its own driver service. This is
* useful if you need to capture the server's log output for a specific session:
*
* var edge = require('selenium-webdriver/edge');
*
* var service = new edge.ServiceBuilder()
* .setPort(55555)
* .build();
*
* var options = new edge.Options();
* // configure browser options ...
*
* 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
* operation, users should start MicrosoftEdge using the
* {@link ./builder.Builder selenium-webdriver.Builder}.
*
* [MicrosoftEdgeDriver]: https://msdn.microsoft.com/en-us/library/mt188085(v=vs.85).aspx
*/
'use strict';
const fs = require('fs'),
util = require('util');
const http = require('./http'),
io = require('./io'),
capabilities = require('./lib/capabilities'),
promise = require('./lib/promise'),
Symbols = require('./lib/symbols'),
webdriver = require('./lib/webdriver'),
portprober = require('./net/portprober'),
remote = require('./remote');
const EDGEDRIVER_EXE = 'MicrosoftWebDriver.exe';
/**
* Option keys.
* @enum {string}
*/
const CAPABILITY_KEY = {
PAGE_LOAD_STRATEGY: 'pageLoadStrategy'
};
/**
* Class for managing MicrosoftEdgeDriver specific options.
*/
class Options {
constructor() {
/** @private {!Object} */
this.options_ = {};
/** @private {?capabilities.ProxyConfig} */
this.proxy_ = null;
}
/**
* Extracts the MicrosoftEdgeDriver specific options from the given
* capabilities object.
* @param {!capabilities.Capabilities} caps The capabilities object.
* @return {!Options} The MicrosoftEdgeDriver options.
*/
static fromCapabilities(caps) {
var options = new Options();
var map = options.options_;
Object.keys(CAPABILITY_KEY).forEach(function(key) {
key = CAPABILITY_KEY[key];
if (caps.has(key)) {
map[key] = caps.get(key);
}
});
if (caps.has(capabilities.Capability.PROXY)) {
options.setProxy(caps.get(capabilities.Capability.PROXY));
}
return options;
}
/**
* Sets the proxy settings for the new session.
* @param {capabilities.ProxyConfig} proxy The proxy configuration to use.
* @return {!Options} A self reference.
*/
setProxy(proxy) {
this.proxy_ = proxy;
return this;
}
/**
* Sets the page load strategy for Edge.
* Supported values are "normal", "eager", and "none";
*
* @param {string} pageLoadStrategy The page load strategy to use.
* @return {!Options} A self reference.
*/
setPageLoadStrategy(pageLoadStrategy) {
this.options_[CAPABILITY_KEY.PAGE_LOAD_STRATEGY] =
pageLoadStrategy.toLowerCase();
return this;
}
/**
* Converts this options instance to a {@link capabilities.Capabilities}
* object.
* @param {capabilities.Capabilities=} opt_capabilities The capabilities to
* merge these options into, if any.
* @return {!capabilities.Capabilities} The capabilities.
*/
toCapabilities(opt_capabilities) {
var caps = opt_capabilities || capabilities.Capabilities.edge();
if (this.proxy_) {
caps.set(capabilities.Capability.PROXY, this.proxy_);
}
Object.keys(this.options_).forEach(function(key) {
caps.set(key, this.options_[key]);
}, this);
return caps;
}
/**
* Converts this instance to its JSON wire protocol representation. Note this
* function is an implementation not intended for general use.
* @return {{pageLoadStrategy: (string|undefined)}}
* The JSON wire protocol representation of this instance.
*/
[Symbols.serialize]() {
var json = {};
for (var key in this.options_) {
if (this.options_[key] != null) {
json[key] = this.options_[key];
}
}
return json;
}
}
/**
* Creates {@link remote.DriverService} instances that manage a
* MicrosoftEdgeDriver server in a child process.
*/
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
* the builder will attempt to locate the MicrosoftEdgeDriver on the current
* PATH.
* @throws {Error} If provided executable does not exist, or the
* MicrosoftEdgeDriver cannot be found on the PATH.
*/
constructor(opt_exe) {
let exe = opt_exe || io.findInPath(EDGEDRIVER_EXE, true);
if (!exe) {
throw Error(
'The ' + EDGEDRIVER_EXE + ' could not be found on the current PATH. ' +
'Please download the latest version of the MicrosoftEdgeDriver from ' +
'https://www.microsoft.com/en-us/download/details.aspx?id=48212 and ' +
'ensure it can be found on your PATH.');
}
super(exe);
// Binding to the loopback address will fail if not running with
// administrator privileges. Since we cannot test for that in script
// (or can we?), force the DriverService to use "localhost".
this.setHostname('localhost');
}
}
/** @type {remote.DriverService} */
var defaultService = null;
/**
* Sets the default service to use for new MicrosoftEdgeDriver instances.
* @param {!remote.DriverService} service The service to use.
* @throws {Error} If the default service is currently running.
*/
function setDefaultService(service) {
if (defaultService && defaultService.isRunning()) {
throw Error(
'The previously configured EdgeDriver service is still running. ' +
'You must shut it down before you may adjust its configuration.');
}
defaultService = service;
}
/**
* Returns the default MicrosoftEdgeDriver service. If such a service has
* not been configured, one will be constructed using the default configuration
* for an MicrosoftEdgeDriver executable found on the system PATH.
* @return {!remote.DriverService} The default MicrosoftEdgeDriver service.
*/
function getDefaultService() {
if (!defaultService) {
defaultService = new ServiceBuilder().build();
}
return defaultService;
}
/**
* Creates a new WebDriver client for Microsoft's Edge.
*/
class Driver extends webdriver.WebDriver {
/**
* Creates a new browser session for Microsoft's Edge browser.
*
* @param {(capabilities.Capabilities|Options)=} opt_config The configuration
* options.
* @param {remote.DriverService=} opt_service The session to use; will use
* the {@linkplain #getDefaultService default service} by default.
* @param {promise.ControlFlow=} opt_flow The control flow to use, or
* {@code null} to use the currently active flow.
* @return {!Driver} A new driver instance.
*/
static createSession(opt_config, opt_service, opt_flow) {
var service = opt_service || getDefaultService();
var client = service.start().then(url => new http.HttpClient(url));
var executor = new http.Executor(client);
var caps =
opt_config instanceof Options ? opt_config.toCapabilities() :
(opt_config || capabilities.Capabilities.edge());
return /** @type {!Driver} */(super.createSession(
executor, caps, opt_flow, () => service.kill()));
}
/**
* This function is a no-op as file detectors are not supported by this
* implementation.
* @override
*/
setFileDetector() {}
}
// PUBLIC API
exports.Driver = Driver;
exports.Options = Options;
exports.ServiceBuilder = ServiceBuilder;
exports.getDefaultService = getDefaultService;
exports.setDefaultService = setDefaultService;

View file

@ -0,0 +1,42 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview A basic example of working with Chrome on Android. Before
* running this example, you must start adb and connect a device (or start an
* AVD).
*/
'use strict';
const {Builder, By, Key, promise, until} = require('..');
const {Options} = require('../chrome');
promise.consume(function* () {
let driver;
try {
driver = yield new Builder()
.forBrowser('chrome')
.setChromeOptions(new Options().androidChrome())
.build();
yield driver.get('http://www.google.com/ncr');
yield driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
yield driver.wait(until.titleIs('webdriver - Google Search'), 1000);
} finally {
yield driver && driver.quit();
}
}).then(_ => console.log('SUCCESS'), err => console.error('ERROR: ' + err));

View file

@ -0,0 +1,42 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview This is an example of emulating a mobile device using the
* ChromeDriver.
*/
'use strict';
const {Builder, By, Key, promise, until} = require('..');
const {Options} = require('../chrome');
promise.consume(function* () {
let driver;
try {
driver = yield new Builder()
.forBrowser('chrome')
.setChromeOptions(
new Options().setMobileEmulation({deviceName: 'Nexus 5X'}))
.build();
yield driver.get('http://www.google.com/ncr');
yield driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
yield driver.wait(until.titleIs('webdriver - Google Search'), 1000);
} finally {
yield driver && driver.quit();
}
}).then(_ => console.log('SUCCESS'), err => console.error('ERROR: ' + err));

View file

@ -0,0 +1,50 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview An example WebDriver script.
*
* Before running this script, ensure that Mozilla's geckodriver is present on
* your system PATH: <https://github.com/mozilla/geckodriver/releases>
*
* Usage:
* // Default behavior
* node selenium-webdriver/example/google_search.js
*
* // Target Chrome locally; the chromedriver must be on your PATH
* SELENIUM_BROWSER=chrome node selenium-webdriver/example/google_search.js
*
* // Use a local copy of the standalone Selenium server
* SELENIUM_SERVER_JAR=/path/to/selenium-server-standalone.jar \
* node selenium-webdriver/example/google_search.js
*
* // Target a remote Selenium server
* SELENIUM_REMOTE_URL=http://www.example.com:4444/wd/hub \
* node selenium-webdriver/example/google_search.js
*/
const {Builder, By, Key, until} = require('..');
var driver = new Builder()
.forBrowser('firefox')
.build();
driver.get('http://www.google.com/ncr')
.then(_ =>
driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN))
.then(_ => driver.wait(until.titleIs('webdriver - Google Search'), 1000))
.then(_ => driver.quit());

View file

@ -0,0 +1,47 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview An example WebDriver script using generator functions.
*
* Before running this script, ensure that Mozilla's geckodriver is present on
* your system PATH: <https://github.com/mozilla/geckodriver/releases>
*
* Usage:
*
* node selenium-webdriver/example/google_search_generator.js
*/
'use strict';
const {Builder, By, Key, promise, until} = require('..');
promise.consume(function* () {
let driver;
try {
driver = yield new Builder().forBrowser('firefox').build();
yield driver.get('http://www.google.com/ncr');
let q = yield driver.findElement(By.name('q'));
yield q.sendKeys('webdriver', Key.RETURN);
yield driver.wait(until.titleIs('webdriver - Google Search'), 1000);
} finally {
yield driver && driver.quit();
}
}).then(_ => console.log('SUCCESS'), err => console.error('ERROR: ' + err));

View file

@ -0,0 +1,60 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview An example test that may be run using Mocha.
*
* Usage:
*
* mocha -t 10000 selenium-webdriver/example/google_search_test.js
*
* You can change which browser is started with the SELENIUM_BROWSER environment
* variable:
*
* SELENIUM_BROWSER=chrome \
* mocha -t 10000 selenium-webdriver/example/google_search_test.js
*/
const {Builder, By, Key, until} = require('..');
const test = require('../testing');
test.describe('Google Search', function() {
let driver;
test.before(function *() {
driver = yield new Builder().forBrowser('firefox').build();
});
// You can write tests either using traditional promises.
it('works with promises', function() {
return driver.get('http://www.google.com/ncr')
.then(_ =>
driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN))
.then(_ => driver.wait(until.titleIs('webdriver - Google Search'), 1000));
});
// Or you can define the test as a generator function. The test will wait for
// any yielded promises to resolve before invoking the next step in the
// generator.
test.it('works with generators', function*() {
yield driver.get('http://www.google.com/ncr');
yield driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
yield driver.wait(until.titleIs('webdriver - Google Search'), 1000);
});
test.after(() => driver.quit());
});

35
node_modules/selenium-webdriver/example/logging.js generated vendored Normal file
View file

@ -0,0 +1,35 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Demonstrates how to use WebDriver's logging sysem.
*/
'use strict';
const {Builder, By, Key, logging, until} = require('..');
logging.installConsoleHandler();
logging.getLogger('webdriver.http').setLevel(logging.Level.ALL);
var driver = new Builder().forBrowser('firefox').build();
driver.get('http://www.google.com/ncr')
.then(_ =>
driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN))
.then(_ => driver.wait(until.titleIs('webdriver - Google Search'), 1000))
.then(_ => driver.quit());

View file

@ -0,0 +1,51 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview An example of starting multiple WebDriver clients that run
* in parallel in separate control flows.
*
* This example will only work when the promise manager is enabled
* (see <https://github.com/SeleniumHQ/selenium/issues/2969>).
*/
const {Builder, By, Key, promise, until} = require('..');
for (var i = 0; i < 3; i++) {
(function(n) {
var flow = new promise.ControlFlow()
.on('uncaughtException', function(e) {
console.log('uncaughtException in flow %d: %s', n, e);
});
var driver = new Builder().
forBrowser('firefox').
setControlFlow(flow). // Comment out this line to see the difference.
build();
// Position and resize window so it's easy to see them running together.
driver.manage().window().setSize(600, 400);
driver.manage().window().setPosition(300 * i, 400 * i);
driver.get('http://www.google.com');
driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
driver.wait(until.titleIs('webdriver - Google Search'), 1000);
driver.quit();
})(i);
}

347
node_modules/selenium-webdriver/firefox/binary.js generated vendored Normal file
View file

@ -0,0 +1,347 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Manages Firefox binaries. This module is considered internal;
* users should use {@link ./firefox selenium-webdriver/firefox}.
*/
'use strict';
const child = require('child_process'),
fs = require('fs'),
path = require('path'),
util = require('util');
const isDevMode = require('../lib/devmode'),
Symbols = require('../lib/symbols'),
io = require('../io'),
exec = require('../io/exec');
/** @const */
const NO_FOCUS_LIB_X86 = isDevMode ?
path.join(__dirname, '../../../../cpp/prebuilt/i386/libnoblur.so') :
path.join(__dirname, '../lib/firefox/i386/libnoblur.so') ;
/** @const */
const NO_FOCUS_LIB_AMD64 = isDevMode ?
path.join(__dirname, '../../../../cpp/prebuilt/amd64/libnoblur64.so') :
path.join(__dirname, '../lib/firefox/amd64/libnoblur64.so') ;
const X_IGNORE_NO_FOCUS_LIB = 'x_ignore_nofocus.so';
/**
* @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 findInProgramFiles(file) {
let files = [
process.env['PROGRAMFILES'] || 'C:\\Program Files',
process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)'
].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;
});
});
}
/**
* 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.
*
* @final
*/
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;
}
/**
* 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_;
}
}
/**
* 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');
/**
* 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');
/**
* 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');
/**
* 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');
/**
* Copies the no focus libs into the given profile directory.
* @param {string} profileDir Path to the profile directory to install into.
* @return {!Promise<string>} The LD_LIBRARY_PATH prefix string to use
* for the installed libs.
*/
function installNoFocusLibs(profileDir) {
var x86 = path.join(profileDir, 'x86');
var amd64 = path.join(profileDir, 'amd64');
return io.mkdir(x86)
.then(() => copyLib(NO_FOCUS_LIB_X86, x86))
.then(() => io.mkdir(amd64))
.then(() => copyLib(NO_FOCUS_LIB_AMD64, amd64))
.then(function() {
return x86 + ':' + amd64;
});
function copyLib(src, dir) {
return io.copy(src, path.join(dir, X_IGNORE_NO_FOCUS_LIB));
}
}
/**
* Provides a mechanism to configure and launch Firefox in a subprocess for
* 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 MacOS and
* Windows, this class will look for Firefox in the current platform's default
* installation location (e.g. /Applications/Firefox.app on MacOS). For all
* other platforms, the Firefox executable must be available on your system
* `PATH`.
*
* @final
* @deprecated This class will be removed in 4.0. Use the binary management
* functions available on the {@link ./index.Options firefox.Options} class.
*/
class Binary {
/**
* @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_exeOrChannel) {
/** @private {?(string|Channel)} */
this.exe_ = opt_exeOrChannel || null;
/** @private {!Array.<string>} */
this.args_ = [];
/** @private {!Object<string, string>} */
this.env_ = {};
Object.assign(this.env_, process.env, {
MOZ_CRASHREPORTER_DISABLE: '1',
MOZ_NO_REMOTE: '1',
NO_EM_RESTART: '1'
});
/** @private {boolean} */
this.devEdition_ = false;
}
/**
* @return {(string|undefined)} The path to the Firefox executable to use, or
* `undefined` if WebDriver should attempt to locate Firefox automatically
* on the current system.
*/
getExe() {
return typeof this.exe_ === 'string' ? this.exe_ : undefined;
}
/**
* Add arguments to the command line used to start Firefox.
* @param {...(string|!Array.<string>)} var_args Either the arguments to add
* as varargs, or the arguments as an array.
* @deprecated Use {@link ./index.Options#addArguments}.
*/
addArguments(var_args) {
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i])) {
this.args_ = this.args_.concat(arguments[i]);
} else {
this.args_.push(arguments[i]);
}
}
}
/**
* @return {!Array<string>} The command line arguments to use when starting
* the browser.
*/
getArguments() {
return this.args_;
}
/**
* Specifies whether to use Firefox Developer Edition instead of the normal
* stable channel. Setting this option has no effect if this instance was
* created with a path to a specific Firefox binary.
*
* This method has no effect on Unix systems where the Firefox application
* has the same (default) name regardless of version.
*
* @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;
}
/**
* Returns a promise for the Firefox executable used by this instance. The
* returned promise will be immediately resolved if the user supplied an
* executable path when this instance was created. Otherwise, an attempt will
* be made to find Firefox on the current system.
*
* @return {!Promise<string>} a promise for the path to the Firefox executable
* used by this instance.
*/
locate() {
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();
}
/**
* Launches Firefox and returns a promise that will be fulfilled when the
* process terminates.
* @param {string} profile Path to the profile directory to use.
* @return {!Promise<!exec.Command>} A promise for the handle to the started
* subprocess.
*/
launch(profile) {
let env = {};
Object.assign(env, this.env_, {XRE_PROFILE_PATH: profile});
let args = ['-foreground'].concat(this.args_);
return this.locate().then(function(firefox) {
if (process.platform === 'win32' || process.platform === 'darwin') {
return exec(firefox, {args: args, env: env});
}
return installNoFocusLibs(profile).then(function(ldLibraryPath) {
env['LD_LIBRARY_PATH'] = ldLibraryPath + ':' + env['LD_LIBRARY_PATH'];
env['LD_PRELOAD'] = X_IGNORE_NO_FOCUS_LIB;
return exec(firefox, {args: args, env: env});
});
});
}
/**
* Returns a promise for the wire representation of this binary. Note: the
* FirefoxDriver only supports passing the path to the binary executable over
* the wire; all command line arguments and environment variables will be
* discarded.
*
* @return {!Promise<string>} A promise for this binary's wire representation.
*/
[Symbols.serialize]() {
return this.locate();
}
}
// PUBLIC API
exports.Binary = Binary;
exports.Channel = Channel;

224
node_modules/selenium-webdriver/firefox/extension.js generated vendored Normal file
View file

@ -0,0 +1,224 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/** @fileoverview Utilities for working with Firefox extensions. */
'use strict';
const fs = require('fs'),
path = require('path'),
xml = require('xml2js');
const io = require('../io');
const zip = require('../io/zip');
/**
* Thrown when there an add-on is malformed.
*/
class AddonFormatError extends Error {
/** @param {string} msg The error message. */
constructor(msg) {
super(msg);
/** @override */
this.name = this.constructor.name;
}
}
/**
* Installs an extension to the given directory.
* @param {string} extension Path to the extension to install, as either a xpi
* file or a directory.
* @param {string} dir Path to the directory to install the extension in.
* @return {!Promise<string>} A promise for the add-on ID once
* installed.
*/
function install(extension, dir) {
return getDetails(extension).then(function(details) {
var dst = path.join(dir, details.id);
if (extension.slice(-4) === '.xpi') {
if (!details.unpack) {
return io.copy(extension, dst + '.xpi').then(() => details.id);
} else {
return zip.unzip(extension, dst).then(() => details.id);
}
} else {
return io.copyDir(extension, dst).then(() => details.id);
}
});
}
/**
* Describes a Firefox add-on.
* @typedef {{id: string, name: string, version: string, unpack: boolean}}
*/
var AddonDetails;
/** @typedef {{$: !Object<string, string>}} */
var RdfRoot;
/**
* Extracts the details needed to install an add-on.
* @param {string} addonPath Path to the extension directory.
* @return {!Promise<!AddonDetails>} A promise for the add-on details.
*/
function getDetails(addonPath) {
return io.stat(addonPath).then((stats) => {
if (stats.isDirectory()) {
return parseDirectory(addonPath);
} else if (addonPath.slice(-4) === '.xpi') {
return parseXpiFile(addonPath);
} else {
throw Error('Add-on path is not an xpi or a directory: ' + addonPath);
}
});
/**
* Parse an install.rdf for a Firefox add-on.
* @param {string} rdf The contents of install.rdf for the add-on.
* @return {!Promise<!AddonDetails>} A promise for the add-on details.
*/
function parseInstallRdf(rdf) {
return parseXml(rdf).then(function(doc) {
var em = getNamespaceId(doc, 'http://www.mozilla.org/2004/em-rdf#');
var rdf = getNamespaceId(
doc, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
var description = doc[rdf + 'RDF'][rdf + 'Description'][0];
var details = {
id: getNodeText(description, em + 'id'),
name: getNodeText(description, em + 'name'),
version: getNodeText(description, em + 'version'),
unpack: getNodeText(description, em + 'unpack') || false
};
if (typeof details.unpack === 'string') {
details.unpack = details.unpack.toLowerCase() === 'true';
}
if (!details.id) {
throw new AddonFormatError('Could not find add-on ID for ' + addonPath);
}
return details;
});
function parseXml(text) {
return new Promise((resolve, reject) => {
xml.parseString(text, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function getNodeText(node, name) {
return node[name] && node[name][0] || '';
}
function getNamespaceId(doc, url) {
var keys = Object.keys(doc);
if (keys.length !== 1) {
throw new AddonFormatError('Malformed manifest for add-on ' + addonPath);
}
var namespaces = /** @type {!RdfRoot} */(doc[keys[0]]).$;
var id = '';
Object.keys(namespaces).some(function(ns) {
if (namespaces[ns] !== url) {
return false;
}
if (ns.indexOf(':') != -1) {
id = ns.split(':')[1] + ':';
}
return true;
});
return id;
}
}
/**
* Parse a manifest for a Firefox WebExtension.
* @param {{
* name: string,
* version: string,
* applications: {gecko:{id:string}}
* }} json JSON representation of the manifest.
* @return {!AddonDetails} The add-on details.
*/
function parseManifestJson({name, version, applications}) {
if (!(applications && applications.gecko && applications.gecko.id)) {
throw new AddonFormatError('Could not find add-on ID for ' + addonPath);
}
return {id: applications.gecko.id, name, version, unpack: false};
}
function parseXpiFile(filePath) {
return zip.load(filePath).then(archive => {
if (archive.has('install.rdf')) {
return archive.getFile('install.rdf')
.then(buf => parseInstallRdf(buf.toString('utf8')));
}
if (archive.has('manifest.json')) {
return archive.getFile('manifest.json')
.then(buf => JSON.parse(buf.toString('utf8')))
.then(parseManifestJson);
}
throw new AddonFormatError(
`Couldn't find install.rdf or manifest.json in ${filePath}`);
});
}
function parseDirectory(dirPath) {
const rdfPath = path.join(dirPath, 'install.rdf');
const jsonPath = path.join(dirPath, 'manifest.json');
return io.exists(rdfPath)
.then(rdfExists => {
if (rdfExists) {
return io.read(rdfPath)
.then(buf => parseInstallRdf(buf.toString('utf8')));
}
return io.exists(jsonPath)
.then(jsonExists => {
if (jsonExists) {
return io.read(jsonPath)
.then(buf => JSON.parse(buf.toString('utf8')))
.then(parseManifestJson);
}
throw new AddonFormatError(
`Couldn't find install.rdf or manifest.json in ${dirPath}`);
});
})
}
}
// PUBLIC API
exports.install = install;

576
node_modules/selenium-webdriver/firefox/index.js generated vendored Normal file
View file

@ -0,0 +1,576 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Defines the {@linkplain Driver WebDriver} client for Firefox.
* Before using this module, you must download the latest
* [geckodriver release] and ensure it can be found on your system [PATH].
*
* Each FirefoxDriver instance will be created with an anonymous profile,
* ensuring browser historys do not share session data (cookies, history, cache,
* offline storage, etc.)
*
* __Customizing the Firefox Profile__
*
* 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:
*
* const {Builder} = require('selenium-webdriver');
* const firefox = require('selenium-webdriver/firefox');
*
* let profile = new firefox.Profile();
* profile.addExtension('/path/to/firebug.xpi');
* profile.setPreference('extensions.firebug.showChromeErrors', true);
*
* let options = new firefox.Options().setProfile(profile);
* let driver = new Builder()
* .forBrowser('firefox')
* .setFirefoxOptions(options)
* .build();
*
* The {@linkplain Profile} class may also be used to configure WebDriver based
* on a pre-existing browser profile:
*
* let profile = new firefox.Profile(
* '/usr/local/home/bob/.mozilla/firefox/3fgog75h.testing');
* 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
* preferences that are required for WebDriver to function properly and they
* will always be overwritten.
*
* __Using a Custom Firefox Binary__
*
* On Windows and MacOS, the FirefoxDriver will search for Firefox in its
* default installation location:
*
* - 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)`.
*
* 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();
*
* On all platforms, you may configrue WebDriver to use a Firefox specific
* executable:
*
* let options = new firefox.Options()
* .setBinary('/my/firefox/install/dir/firefox-bin');
*
* __Remote Testing__
*
* You may customize the Firefox binary and profile when running against a
* remote Selenium server. Your custom profile will be packaged as a zip and
* transfered to the remote host for use. The profile will be transferred
* _once for each new session_. The performance impact should be minimal if
* you've only configured a few extra browser preferences. If you have a large
* profile with several extensions, you should consider installing it on the
* remote host and defining its path via the {@link Options} class. Custom
* binaries are never copied to remote machines and must be referenced by
* installation path.
*
* 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');
*
* let driver = new Builder()
* .forBrowser('firefox')
* .usingServer('http://127.0.0.1:4444/wd/hub')
* .setFirefoxOptions(options)
* .build();
*
* [geckodriver release]: https://github.com/mozilla/geckodriver/releases/
* [PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
*/
'use strict';
const url = require('url');
const {Binary, Channel} = require('./binary'),
Profile = require('./profile').Profile,
http = require('../http'),
httpUtil = require('../http/util'),
io = require('../io'),
capabilities = require('../lib/capabilities'),
command = require('../lib/command'),
logging = require('../lib/logging'),
promise = require('../lib/promise'),
webdriver = require('../lib/webdriver'),
net = require('../net'),
portprober = require('../net/portprober'),
remote = require('../remote');
/**
* Configuration options for the FirefoxDriver.
*/
class Options {
constructor() {
/** @private {Profile} */
this.profile_ = null;
/** @private {(Binary|Channel|string|null)} */
this.binary_ = null;
/** @private {!Array<string>} */
this.args_ = [];
/** @private {logging.Preferences} */
this.logPrefs_ = null;
/** @private {?capabilities.ProxyConfig} */
this.proxy_ = null;
}
/**
* Specify additional command line arguments that should be used when starting
* the Firefox browser.
*
* @param {...(string|!Array<string>)} args The arguments to include.
* @return {!Options} A self reference.
*/
addArguments(...args) {
this.args_ = this.args_.concat(...args);
return this;
}
/**
* Configures the geckodriver to start Firefox in headless mode.
*
* @return {!Options} A self reference.
*/
headless() {
return this.addArguments('-headless');
}
/**
* Sets the initial window size when running in
* {@linkplain #headless headless} mode.
*
* @param {{width: number, height: number}} size The desired window size.
* @return {!Options} A self reference.
* @throws {TypeError} if width or height is unspecified, not a number, or
* less than or equal to 0.
*/
windowSize({width, height}) {
function checkArg(arg) {
if (typeof arg !== 'number' || arg <= 0) {
throw TypeError('Arguments must be {width, height} with numbers > 0');
}
}
checkArg(width);
checkArg(height);
return this.addArguments(`--window-size=${width},${height}`);
}
/**
* Sets the profile to use. The profile may be specified as a
* {@link Profile} object or as the path to an existing Firefox profile to use
* as a template.
*
* @param {(string|!Profile)} profile The profile to use.
* @return {!Options} A self reference.
*/
setProfile(profile) {
if (typeof profile === 'string') {
profile = new Profile(profile);
}
this.profile_ = profile;
return this;
}
/**
* 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|!Channel)} binary The binary to use.
* @return {!Options} A self reference.
* @throws {TypeError} If `binary` is an invalid type.
*/
setBinary(binary) {
if (binary instanceof Binary
|| binary instanceof Channel
|| typeof binary === 'string') {
this.binary_ = binary;
return this;
}
throw TypeError(
'binary must be a string path, Channel, or Binary object');
}
/**
* Sets the logging preferences for the new session.
* @param {logging.Preferences} prefs The logging preferences.
* @return {!Options} A self reference.
*/
setLoggingPreferences(prefs) {
this.logPrefs_ = prefs;
return this;
}
/**
* Sets the proxy to use.
*
* @param {capabilities.ProxyConfig} proxy The proxy configuration to use.
* @return {!Options} A self reference.
*/
setProxy(proxy) {
this.proxy_ = proxy;
return this;
}
/**
* Converts these options to a {@link capabilities.Capabilities} instance.
*
* @return {!capabilities.Capabilities} A new capabilities object.
*/
toCapabilities() {
let caps = capabilities.Capabilities.firefox();
let firefoxOptions = {};
caps.set('moz:firefoxOptions', firefoxOptions);
if (this.logPrefs_) {
caps.set(capabilities.Capability.LOGGING_PREFS, this.logPrefs_);
}
if (this.proxy_) {
caps.set(capabilities.Capability.PROXY, this.proxy_);
}
if (this.args_.length) {
firefoxOptions['args'] = this.args_.concat();
}
if (this.binary_) {
if (this.binary_ instanceof Binary) {
let exe = this.binary_.getExe();
if (exe) {
firefoxOptions['binary'] = exe;
}
let args = this.binary_.getArguments();
if (args.length) {
if (this.args_.length) {
throw Error(
'You may specify browser arguments with Options.addArguments'
+ ' (preferred) or Binary.addArguments, but not both');
}
firefoxOptions['args'] = args;
}
} else if (this.binary_ instanceof Channel) {
firefoxOptions['binary'] = this.binary_.locate();
} else if (typeof this.binary_ === 'string') {
firefoxOptions['binary'] = this.binary_;
}
}
if (this.profile_) {
// If the user specified a template directory or any extensions to
// install, we need to encode the profile as a base64 string (which
// requires writing it to disk first). Otherwise, if the user just
// specified some custom preferences, we can send those directly.
let profile = this.profile_;
if (profile.getTemplateDir() || profile.getExtensions().length) {
firefoxOptions['profile'] = profile.encode();
} else {
let prefs = profile.getPreferences();
if (Object.keys(prefs).length) {
firefoxOptions['prefs'] = prefs;
}
}
}
return caps;
}
}
/**
* Enum of available command contexts.
*
* Command contexts are specific to Marionette, and may be used with the
* {@link #context=} method. Contexts allow you to direct all subsequent
* commands to either "content" (default) or "chrome". The latter gives
* you elevated security permissions.
*
* @enum {string}
*/
const Context = {
CONTENT: "content",
CHROME: "chrome",
};
const GECKO_DRIVER_EXE =
process.platform === 'win32' ? 'geckodriver.exe' : 'geckodriver';
/**
* @return {string} .
* @throws {Error}
*/
function findGeckoDriver() {
let exe = io.findInPath(GECKO_DRIVER_EXE, true);
if (!exe) {
throw Error(
'The ' + GECKO_DRIVER_EXE + ' executable could not be found on the current ' +
'PATH. Please download the latest version from ' +
'https://github.com/mozilla/geckodriver/releases/ ' +
'and ensure it can be found on your PATH.');
}
return exe;
}
function normalizeProxyConfiguration(config) {
if ('manual' === config.proxyType) {
if (config.ftpProxy && !config.ftpProxyPort) {
let hostAndPort = net.splitHostAndPort(config.ftpProxy);
config.ftpProxy = hostAndPort.host;
config.ftpProxyPort = hostAndPort.port;
}
if (config.httpProxy && !config.httpProxyPort) {
let hostAndPort = net.splitHostAndPort(config.httpProxy);
config.httpProxy = hostAndPort.host;
config.httpProxyPort = hostAndPort.port;
}
if (config.sslProxy && !config.sslProxyPort) {
let hostAndPort = net.splitHostAndPort(config.sslProxy);
config.sslProxy = hostAndPort.host;
config.sslProxyPort = hostAndPort.port;
}
if (config.socksProxy && !config.socksProxyPort) {
let hostAndPort = net.splitHostAndPort(config.socksProxy);
config.socksProxy = hostAndPort.host;
config.socksProxyPort = hostAndPort.port;
}
} else if ('pac' === config.proxyType) {
if (config.proxyAutoconfigUrl && !config.pacUrl) {
config.pacUrl = config.proxyAutoconfigUrl;
}
}
return config;
}
/** @enum {string} */
const ExtensionCommand = {
GET_CONTEXT: 'getContext',
SET_CONTEXT: 'setContext',
};
/**
* Creates a command executor with support for Marionette's custom commands.
* @param {!Promise<string>} serverUrl The server's URL.
* @return {!command.Executor} The new command executor.
*/
function createExecutor(serverUrl) {
let client = serverUrl.then(url => new http.HttpClient(url));
let executor = new http.Executor(client);
configureExecutor(executor);
return executor;
}
/**
* Configures the given executor with Firefox-specific commands.
* @param {!http.Executor} executor the executor to configure.
*/
function configureExecutor(executor) {
executor.defineCommand(
ExtensionCommand.GET_CONTEXT,
'GET',
'/session/:sessionId/moz/context');
executor.defineCommand(
ExtensionCommand.SET_CONTEXT,
'POST',
'/session/:sessionId/moz/context');
}
/**
* Creates {@link selenium-webdriver/remote.DriverService} instances that manage
* a [geckodriver](https://github.com/mozilla/geckodriver) server in a child
* process.
*/
class ServiceBuilder extends remote.DriverService.Builder {
/**
* @param {string=} opt_exe Path to the server executable to use. If omitted,
* the builder will attempt to locate the geckodriver on the system PATH.
*/
constructor(opt_exe) {
super(opt_exe || findGeckoDriver());
this.setLoopback(true); // Required.
}
/**
* Enables verbose logging.
*
* @param {boolean=} opt_trace Whether to enable trace-level logging. By
* default, only debug logging is enabled.
* @return {!ServiceBuilder} A self reference.
*/
enableVerboseLogging(opt_trace) {
return this.addArguments(opt_trace ? '-vv' : '-v');
}
}
/**
* A WebDriver client for Firefox.
*/
class Driver extends webdriver.WebDriver {
/**
* Creates a new Firefox session.
*
* @param {(Options|capabilities.Capabilities|Object)=} opt_config The
* configuration options for this driver, specified as either an
* {@link Options} or {@link capabilities.Capabilities}, or as a raw hash
* object.
* @param {(http.Executor|remote.DriverService)=} opt_executor Either a
* pre-configured command executor to use for communicating with an
* externally managed remote end (which is assumed to already be running),
* or the `DriverService` to use to start the geckodriver in a child
* process.
*
* If an executor is provided, care should e taken not to use reuse it with
* other clients as its internal command mappings will be updated to support
* Firefox-specific commands.
*
* _This parameter may only be used with Mozilla's GeckoDriver._
*
* @param {promise.ControlFlow=} opt_flow The flow to
* schedule commands through. Defaults to the active flow object.
* @throws {Error} If a custom command executor is provided and the driver is
* configured to use the legacy FirefoxDriver from the Selenium project.
* @return {!Driver} A new driver instance.
*/
static createSession(opt_config, opt_executor, opt_flow) {
let caps;
if (opt_config instanceof Options) {
caps = opt_config.toCapabilities();
} else {
caps = new capabilities.Capabilities(opt_config);
}
if (caps.has(capabilities.Capability.PROXY)) {
let proxy =
normalizeProxyConfiguration(caps.get(capabilities.Capability.PROXY));
caps.set(capabilities.Capability.PROXY, proxy);
}
let executor;
let onQuit;
if (opt_executor instanceof http.Executor) {
executor = opt_executor;
configureExecutor(executor);
} else if (opt_executor instanceof remote.DriverService) {
executor = createExecutor(opt_executor.start());
onQuit = () => opt_executor.kill();
} else {
let service = new ServiceBuilder().build();
executor = createExecutor(service.start());
onQuit = () => service.kill();
}
return /** @type {!Driver} */(super.createSession(
executor, caps, opt_flow, onQuit));
}
/**
* This function is a no-op as file detectors are not supported by this
* implementation.
* @override
*/
setFileDetector() {
}
/**
* Get the context that is currently in effect.
*
* @return {!promise.Thenable<Context>} Current context.
*/
getContext() {
return this.schedule(
new command.Command(ExtensionCommand.GET_CONTEXT),
'get WebDriver.context');
}
/**
* Changes target context for commands between chrome- and content.
*
* Changing the current context has a stateful impact on all subsequent
* commands. The {@link Context.CONTENT} context has normal web
* platform document permissions, as if you would evaluate arbitrary
* JavaScript. The {@link Context.CHROME} context gets elevated
* permissions that lets you manipulate the browser chrome itself,
* with full access to the XUL toolkit.
*
* Use your powers wisely.
*
* @param {!promise.Thenable<void>} ctx The context to switch to.
*/
setContext(ctx) {
return this.schedule(
new command.Command(ExtensionCommand.SET_CONTEXT)
.setParameter("context", ctx),
'set WebDriver.context');
}
}
// PUBLIC API
exports.Binary = Binary;
exports.Channel = Channel;
exports.Context = Context;
exports.Driver = Driver;
exports.Options = Options;
exports.Profile = Profile;
exports.ServiceBuilder = ServiceBuilder;

311
node_modules/selenium-webdriver/firefox/profile.js generated vendored Normal file
View file

@ -0,0 +1,311 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Profile management module. This module is considered internal;
* users should use {@link selenium-webdriver/firefox}.
*/
'use strict';
const fs = require('fs'),
path = require('path'),
vm = require('vm');
const isDevMode = require('../lib/devmode'),
Symbols = require('../lib/symbols'),
io = require('../io'),
{Zip, unzip} = require('../io/zip'),
extension = require('./extension');
/**
* Parses a user.js file in a Firefox profile directory.
* @param {string} f Path to the file to parse.
* @return {!Promise<!Object>} A promise for the parsed preferences as
* a JSON object. If the file does not exist, an empty object will be
* returned.
*/
function loadUserPrefs(f) {
return io.read(f).then(
function onSuccess(contents) {
var prefs = {};
var context = vm.createContext({
'user_pref': function(key, value) {
prefs[key] = value;
}
});
vm.runInContext(contents.toString(), context, f);
return prefs;
},
function onError(err) {
if (err && err.code === 'ENOENT') {
return {};
}
throw err;
});
}
/**
* @param {!Object} prefs The default preferences to write. Will be
* overridden by user.js preferences in the template directory and the
* frozen preferences required by WebDriver.
* @param {string} dir Path to the directory write the file to.
* @return {!Promise<string>} A promise for the profile directory,
* to be fulfilled when user preferences have been written.
*/
function writeUserPrefs(prefs, dir) {
var userPrefs = path.join(dir, 'user.js');
return loadUserPrefs(userPrefs).then(function(overrides) {
Object.assign(prefs, overrides);
let keys = Object.keys(prefs);
if (!keys.length) {
return dir;
}
let contents = Object.keys(prefs).map(function(key) {
return 'user_pref(' + JSON.stringify(key) + ', ' +
JSON.stringify(prefs[key]) + ');';
}).join('\n');
return new Promise((resolve, reject) => {
fs.writeFile(userPrefs, contents, function(err) {
err && reject(err) || resolve(dir);
});
});
});
};
/**
* Installs a group of extensions in the given profile directory. If the
* WebDriver extension is not included in this set, the default version
* bundled with this package will be installed.
* @param {!Array.<string>} extensions The extensions to install, as a
* path to an unpacked extension directory or a path to a xpi file.
* @param {string} dir The profile directory to install to.
* @return {!Promise<string>} A promise for the main profile directory
* once all extensions have been installed.
*/
function installExtensions(extensions, dir) {
var next = 0;
var extensionDir = path.join(dir, 'extensions');
return new Promise(function(fulfill, reject) {
io.mkdir(extensionDir).then(installNext, reject);
function installNext() {
if (next >= extensions.length) {
fulfill(dir);
} else {
install(extensions[next++]);
}
}
function install(ext) {
extension.install(ext, extensionDir).then(function(id) {
installNext();
}, reject);
}
});
}
/**
* Models a Firefox profile directory for use with the FirefoxDriver. The
* {@code Profile} directory uses an in-memory model until
* {@link #writeToDisk} or {@link #encode} is called.
*/
class Profile {
/**
* @param {string=} opt_dir Path to an existing Firefox profile directory to
* use a template for this profile. If not specified, a blank profile will
* be used.
*/
constructor(opt_dir) {
/** @private {!Object} */
this.preferences_ = {};
/** @private {(string|undefined)} */
this.template_ = opt_dir;
/** @private {!Array<string>} */
this.extensions_ = [];
}
/**
* @return {(string|undefined)} Path to an existing Firefox profile directory
* to use as a template when writing this Profile to disk.
*/
getTemplateDir() {
return this.template_;
}
/**
* Registers an extension to be included with this profile.
* @param {string} extension Path to the extension to include, as either an
* unpacked extension directory or the path to a xpi file.
*/
addExtension(extension) {
this.extensions_.push(extension);
}
/**
* @return {!Array<string>} A list of extensions to install in this profile.
*/
getExtensions() {
return this.extensions_;
}
/**
* Sets a desired preference for this profile.
* @param {string} key The preference key.
* @param {(string|number|boolean)} value The preference value.
* @throws {Error} If attempting to set a frozen preference.
*/
setPreference(key, value) {
this.preferences_[key] = value;
}
/**
* Returns the currently configured value of a profile preference. This does
* not include any defaults defined in the profile's template directory user.js
* file (if a template were specified on construction).
* @param {string} key The desired preference.
* @return {(string|number|boolean|undefined)} The current value of the
* requested preference.
*/
getPreference(key) {
return this.preferences_[key];
}
/**
* @return {!Object} A copy of all currently configured preferences.
*/
getPreferences() {
return Object.assign({}, this.preferences_);
}
/**
* Specifies which host the driver should listen for commands on. If not
* specified, the driver will default to "localhost". This option should be
* specified when "localhost" is not mapped to the loopback address
* (127.0.0.1) in `/etc/hosts`.
*
* @param {string} host the host the driver should listen for commands on
*/
setHost(host) {
this.preferences_['webdriver_firefox_allowed_hosts'] = host;
}
/**
* @return {boolean} Whether the FirefoxDriver is configured to automatically
* accept untrusted SSL certificates.
*/
acceptUntrustedCerts() {
return !!this.preferences_['webdriver_accept_untrusted_certs'];
}
/**
* Sets whether the FirefoxDriver should automatically accept untrusted SSL
* certificates.
* @param {boolean} value .
*/
setAcceptUntrustedCerts(value) {
this.preferences_['webdriver_accept_untrusted_certs'] = !!value;
}
/**
* Sets whether to assume untrusted certificates come from untrusted issuers.
* @param {boolean} value .
*/
setAssumeUntrustedCertIssuer(value) {
this.preferences_['webdriver_assume_untrusted_issuer'] = !!value;
}
/**
* @return {boolean} Whether to assume untrusted certs come from untrusted
* issuers.
*/
assumeUntrustedCertIssuer() {
return !!this.preferences_['webdriver_assume_untrusted_issuer'];
}
/**
* Writes this profile to disk.
* @return {!Promise<string>} A promise for the path to the new profile
* directory.
*/
writeToDisk() {
var profileDir = io.tmpDir();
if (this.template_) {
profileDir = profileDir.then(function(dir) {
return io.copyDir(
/** @type {string} */(this.template_),
dir, /(parent\.lock|lock|\.parentlock)/);
}.bind(this));
}
// Freeze preferences for async operations.
let prefs = Object.assign({}, this.preferences_);
// Freeze extensions for async operations.
var extensions = this.extensions_.concat();
return profileDir.then(function(dir) {
return writeUserPrefs(prefs, dir);
}).then(function(dir) {
return installExtensions(extensions, dir);
});
}
/**
* Write profile to disk, compress its containing directory, and return
* it as a Base64 encoded string.
*
* @return {!Promise<string>} A promise for the encoded profile as
* Base64 string.
*
*/
encode() {
return this.writeToDisk().then(function(dir) {
let zip = new Zip;
return zip.addDir(dir)
.then(() => zip.toBuffer())
.then(buf => buf.toString('base64'));
});
}
/**
* Encodes this profile as a zipped, base64 encoded directory.
* @return {!Promise<string>} A promise for the encoded profile.
*/
[Symbols.serialize]() {
return this.encode();
}
}
// PUBLIC API
exports.Profile = Profile;
exports.loadUserPrefs = loadUserPrefs;

255
node_modules/selenium-webdriver/http/index.js generated vendored Normal file
View file

@ -0,0 +1,255 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Defines an {@linkplain cmd.Executor command executor} that
* communicates with a remote end using HTTP + JSON.
*/
'use strict';
const http = require('http');
const https = require('https');
const url = require('url');
const httpLib = require('../lib/http');
/**
* @typedef {{protocol: (?string|undefined),
* auth: (?string|undefined),
* hostname: (?string|undefined),
* host: (?string|undefined),
* port: (?string|undefined),
* path: (?string|undefined),
* pathname: (?string|undefined)}}
*/
var RequestOptions;
/**
* @param {string} aUrl The request URL to parse.
* @return {RequestOptions} The request options.
* @throws {Error} if the URL does not include a hostname.
*/
function getRequestOptions(aUrl) {
let options = url.parse(aUrl);
if (!options.hostname) {
throw new Error('Invalid URL: ' + aUrl);
}
// Delete the search and has portions as they are not used.
options.search = null;
options.hash = null;
options.path = options.pathname;
return options;
}
/**
* A basic HTTP client used to send messages to a remote end.
*
* @implements {httpLib.Client}
*/
class HttpClient {
/**
* @param {string} serverUrl URL for the WebDriver server to send commands to.
* @param {http.Agent=} opt_agent The agent to use for each request.
* Defaults to `http.globalAgent`.
* @param {?string=} opt_proxy The proxy to use for the connection to the
* server. Default is to use no proxy.
*/
constructor(serverUrl, opt_agent, opt_proxy) {
/** @private {http.Agent} */
this.agent_ = opt_agent || null;
/**
* Base options for each request.
* @private {RequestOptions}
*/
this.options_ = getRequestOptions(serverUrl);
/**
* @private {?RequestOptions}
*/
this.proxyOptions_ = opt_proxy ? getRequestOptions(opt_proxy) : null;
}
/** @override */
send(httpRequest) {
let data;
let headers = {};
httpRequest.headers.forEach(function(value, name) {
headers[name] = value;
});
headers['Content-Length'] = 0;
if (httpRequest.method == 'POST' || httpRequest.method == 'PUT') {
data = JSON.stringify(httpRequest.data);
headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
headers['Content-Type'] = 'application/json;charset=UTF-8';
}
let path = this.options_.path;
if (path.endsWith('/') && httpRequest.path.startsWith('/')) {
path += httpRequest.path.substring(1);
} else {
path += httpRequest.path;
}
let parsedPath = url.parse(path);
let options = {
agent: this.agent_ || null,
method: httpRequest.method,
auth: this.options_.auth,
hostname: this.options_.hostname,
port: this.options_.port,
protocol: this.options_.protocol,
path: parsedPath.path,
pathname: parsedPath.pathname,
search: parsedPath.search,
hash: parsedPath.hash,
headers,
};
return new Promise((fulfill, reject) => {
sendRequest(options, fulfill, reject, data, this.proxyOptions_);
});
}
}
/**
* Sends a single HTTP request.
* @param {!Object} options The request options.
* @param {function(!httpLib.Response)} onOk The function to call if the
* request succeeds.
* @param {function(!Error)} onError The function to call if the request fails.
* @param {?string=} opt_data The data to send with the request.
* @param {?RequestOptions=} opt_proxy The proxy server to use for the request.
*/
function sendRequest(options, onOk, onError, opt_data, opt_proxy) {
var hostname = options.hostname;
var port = options.port;
if (opt_proxy) {
let proxy = /** @type {RequestOptions} */(opt_proxy);
// RFC 2616, section 5.1.2:
// The absoluteURI form is REQUIRED when the request is being made to a
// proxy.
let absoluteUri = url.format(options);
// RFC 2616, section 14.23:
// An HTTP/1.1 proxy MUST ensure that any request message it forwards does
// contain an appropriate Host header field that identifies the service
// being requested by the proxy.
let targetHost = options.hostname
if (options.port) {
targetHost += ':' + options.port;
}
// Update the request options with our proxy info.
options.headers['Host'] = targetHost;
options.path = absoluteUri;
options.host = proxy.host;
options.hostname = proxy.hostname;
options.port = proxy.port;
if (proxy.auth) {
options.headers['Proxy-Authorization'] =
'Basic ' + new Buffer(proxy.auth).toString('base64');
}
}
let requestFn = options.protocol === 'https:' ? https.request : http.request;
var request = requestFn(options, function onResponse(response) {
if (response.statusCode == 302 || response.statusCode == 303) {
try {
var location = url.parse(response.headers['location']);
} catch (ex) {
onError(Error(
'Failed to parse "Location" header for server redirect: ' +
ex.message + '\nResponse was: \n' +
new httpLib.Response(response.statusCode, response.headers, '')));
return;
}
if (!location.hostname) {
location.hostname = hostname;
location.port = port;
}
request.abort();
sendRequest({
method: 'GET',
protocol: location.protocol || options.protocol,
hostname: location.hostname,
port: location.port,
path: location.path,
pathname: location.pathname,
search: location.search,
hash: location.hash,
headers: {
'Accept': 'application/json; charset=utf-8'
}
}, onOk, onError, undefined, opt_proxy);
return;
}
var body = [];
response.on('data', body.push.bind(body));
response.on('end', function() {
var resp = new httpLib.Response(
/** @type {number} */(response.statusCode),
/** @type {!Object<string>} */(response.headers),
body.join('').replace(/\0/g, ''));
onOk(resp);
});
});
request.on('error', function(e) {
if (e.code === 'ECONNRESET') {
setTimeout(function() {
sendRequest(options, onOk, onError, opt_data, opt_proxy);
}, 15);
} else {
var message = e.message;
if (e.code) {
message = e.code + ' ' + message;
}
onError(new Error(message));
}
});
if (opt_data) {
request.write(opt_data);
}
request.end();
}
// PUBLIC API
exports.Executor = httpLib.Executor;
exports.HttpClient = HttpClient;
exports.Request = httpLib.Request;
exports.Response = httpLib.Response;

175
node_modules/selenium-webdriver/http/util.js generated vendored Normal file
View file

@ -0,0 +1,175 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Various HTTP utilities.
*/
'use strict';
const Executor = require('./index').Executor,
HttpClient = require('./index').HttpClient,
HttpRequest = require('./index').Request,
Command = require('../lib/command').Command,
CommandName = require('../lib/command').Name,
error = require('../lib/error'),
promise = require('../lib/promise');
/**
* Queries a WebDriver server for its current status.
* @param {string} url Base URL of the server to query.
* @return {!Promise<!Object>} A promise that resolves with
* a hash of the server status.
*/
function getStatus(url) {
var client = new HttpClient(url);
var executor = new Executor(client);
var command = new Command(CommandName.GET_SERVER_STATUS);
return executor.execute(command);
}
// PUBLIC API
/**
* Queries a WebDriver server for its current status.
* @param {string} url Base URL of the server to query.
* @return {!Promise<!Object>} A promise that resolves with
* a hash of the server status.
*/
exports.getStatus = getStatus;
/**
* Waits for a WebDriver server to be healthy and accepting requests.
* @param {string} url Base URL of the server to query.
* @param {number} timeout How long to wait for the server.
* @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
* if resolved before the server is ready, the wait will be terminated
* early with a {@link promise.CancellationError}.
* @return {!Promise} A promise that will resolve when the server is ready, or
* if the wait is cancelled.
*/
exports.waitForServer = function(url, timeout, opt_cancelToken) {
return new Promise((onResolve, onReject) => {
let start = Date.now();
let done = false;
let resolve = (status) => {
done = true;
onResolve(status);
};
let reject = (err) => {
done = true;
onReject(err);
};
if (opt_cancelToken) {
opt_cancelToken.then(_ => reject(new promise.CancellationError));
}
checkServerStatus();
function checkServerStatus() {
return getStatus(url).then(status => resolve(status), onError);
}
function onError(e) {
// Some servers don't support the status command. If they are able to
// response with an error, then can consider the server ready.
if (e instanceof error.UnsupportedOperationError) {
resolve({});
return;
}
if (Date.now() - start > timeout) {
reject(Error('Timed out waiting for the WebDriver server at ' + url));
} else {
setTimeout(function() {
if (!done) {
checkServerStatus();
}
}, 50);
}
}
});
};
/**
* Polls a URL with GET requests until it returns a 2xx response or the
* timeout expires.
* @param {string} url The URL to poll.
* @param {number} timeout How long to wait, in milliseconds.
* @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
* if resolved before the a 2xx response is received, the wait will be
* terminated early with a {@link promise.CancellationError}.
* @return {!Promise} A promise that will resolve when a 2xx is received from
* the given URL, or if the wait is cancelled.
*/
exports.waitForUrl = function(url, timeout, opt_cancelToken) {
return new Promise((onResolve, onReject) => {
let client = new HttpClient(url);
let request = new HttpRequest('GET', '');
let start = Date.now();
let done = false;
let resolve = () => {
done = true;
onResolve();
};
let reject = (err) => {
done = true;
onReject(err);
};
if (opt_cancelToken) {
opt_cancelToken.then(_ => reject(new promise.CancellationError));
}
testUrl();
function testUrl() {
client.send(request).then(onResponse, onError);
}
function onError() {
if (Date.now() - start > timeout) {
reject(Error('Timed out waiting for the URL to return 2xx: ' + url));
} else {
setTimeout(function() {
if (!done) {
testUrl();
}
}, 50);
}
}
function onResponse(response) {
if (done) {
return;
}
if (response.status > 199 && response.status < 300) {
resolve();
return;
}
onError();
}
});
};

441
node_modules/selenium-webdriver/ie.js generated vendored Normal file
View file

@ -0,0 +1,441 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Defines a {@linkplain Driver WebDriver} client for Microsoft's
* Internet Explorer. Before using the IEDriver, you must download the latest
* [IEDriverServer](http://selenium-release.storage.googleapis.com/index.html)
* and place it on your
* [PATH](http://en.wikipedia.org/wiki/PATH_%28variable%29). You must also apply
* the system configuration outlined on the Selenium project
* [wiki](https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver)
*/
'use strict';
const fs = require('fs'),
util = require('util');
const http = require('./http'),
io = require('./io'),
capabilities = require('./lib/capabilities'),
promise = require('./lib/promise'),
webdriver = require('./lib/webdriver'),
portprober = require('./net/portprober'),
remote = require('./remote');
const IEDRIVER_EXE = 'IEDriverServer.exe';
/**
* IEDriverServer logging levels.
* @enum {string}
*/
const Level = {
FATAL: 'FATAL',
ERROR: 'ERROR',
WARN: 'WARN',
INFO: 'INFO',
DEBUG: 'DEBUG',
TRACE: 'TRACE'
};
/**
* Option keys:
* https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#ie-specific
* @enum {string}
*/
const Key = {
IGNORE_PROTECTED_MODE_SETTINGS: 'ignoreProtectedModeSettings',
IGNORE_ZOOM_SETTING: 'ignoreZoomSetting',
INITIAL_BROWSER_URL: 'initialBrowserUrl',
ENABLE_PERSISTENT_HOVER: 'enablePersistentHover',
ENABLE_ELEMENT_CACHE_CLEANUP: 'enableElementCacheCleanup',
REQUIRE_WINDOW_FOCUS: 'requireWindowFocus',
BROWSER_ATTACH_TIMEOUT: 'browserAttachTimeout',
FORCE_CREATE_PROCESS: 'ie.forceCreateProcessApi',
BROWSER_COMMAND_LINE_SWITCHES: 'ie.browserCommandLineSwitches',
USE_PER_PROCESS_PROXY: 'ie.usePerProcessProxy',
ENSURE_CLEAN_SESSION: 'ie.ensureCleanSession',
LOG_FILE: 'logFile',
LOG_LEVEL: 'logLevel',
HOST: 'host',
EXTRACT_PATH: 'extractPath',
SILENT: 'silent'
};
/**
* Class for managing IEDriver specific options.
*/
class Options {
constructor() {
/** @private {!Object<(boolean|number|string|!Array<string>)>} */
this.options_ = {};
/** @private {(capabilities.ProxyConfig|null)} */
this.proxy_ = null;
}
/**
* Extracts the IEDriver specific options from the given capabilities
* object.
* @param {!capabilities.Capabilities} caps The capabilities object.
* @return {!Options} The IEDriver options.
*/
static fromCapabilities(caps) {
var options = new Options();
var map = options.options_;
Object.keys(Key).forEach(function(key) {
key = Key[key];
if (caps.has(key)) {
map[key] = caps.get(key);
}
});
if (caps.has(capabilities.Capability.PROXY)) {
options.setProxy(caps.get(capabilities.Capability.PROXY));
}
return options;
}
/**
* Whether to disable the protected mode settings check when the session is
* created. Disbling this setting may lead to significant instability as the
* browser may become unresponsive/hang. Only "best effort" support is provided
* when using this capability.
*
* For more information, refer to the IEDriver's
* [required system configuration](http://goo.gl/eH0Yi3).
*
* @param {boolean} ignoreSettings Whether to ignore protected mode settings.
* @return {!Options} A self reference.
*/
introduceFlakinessByIgnoringProtectedModeSettings(ignoreSettings) {
this.options_[Key.IGNORE_PROTECTED_MODE_SETTINGS] = !!ignoreSettings;
return this;
}
/**
* Indicates whether to skip the check that the browser's zoom level is set to
* 100%.
*
* @param {boolean} ignore Whether to ignore the browser's zoom level settings.
* @return {!Options} A self reference.
*/
ignoreZoomSetting(ignore) {
this.options_[Key.IGNORE_ZOOM_SETTING] = !!ignore;
return this;
}
/**
* Sets the initial URL loaded when IE starts. This is intended to be used with
* {@link #ignoreProtectedModeSettings} to allow the user to initialize IE in
* the proper Protected Mode zone. Setting this option may cause browser
* instability or flaky and unresponsive code. Only "best effort" support is
* provided when using this option.
*
* @param {string} url The initial browser URL.
* @return {!Options} A self reference.
*/
initialBrowserUrl(url) {
this.options_[Key.INITIAL_BROWSER_URL] = url;
return this;
}
/**
* Configures whether to enable persistent mouse hovering (true by default).
* Persistent hovering is achieved by continuously firing mouse over events at
* the last location the mouse cursor has been moved to.
*
* @param {boolean} enable Whether to enable persistent hovering.
* @return {!Options} A self reference.
*/
enablePersistentHover(enable) {
this.options_[Key.ENABLE_PERSISTENT_HOVER] = !!enable;
return this;
}
/**
* Configures whether the driver should attempt to remove obsolete
* {@linkplain webdriver.WebElement WebElements} from its internal cache on
* page navigation (true by default). Disabling this option will cause the
* driver to run with a larger memory footprint.
*
* @param {boolean} enable Whether to enable element reference cleanup.
* @return {!Options} A self reference.
*/
enableElementCacheCleanup(enable) {
this.options_[Key.ENABLE_ELEMENT_CACHE_CLEANUP] = !!enable;
return this;
}
/**
* Configures whether to require the IE window to have input focus before
* performing any user interactions (i.e. mouse or keyboard events). This
* option is disabled by default, but delivers much more accurate interaction
* events when enabled.
*
* @param {boolean} require Whether to require window focus.
* @return {!Options} A self reference.
*/
requireWindowFocus(require) {
this.options_[Key.REQUIRE_WINDOW_FOCUS] = !!require;
return this;
}
/**
* Configures the timeout, in milliseconds, that the driver will attempt to
* located and attach to a newly opened instance of Internet Explorer. The
* default is zero, which indicates waiting indefinitely.
*
* @param {number} timeout How long to wait for IE.
* @return {!Options} A self reference.
*/
browserAttachTimeout(timeout) {
this.options_[Key.BROWSER_ATTACH_TIMEOUT] = Math.max(timeout, 0);
return this;
}
/**
* Configures whether to launch Internet Explorer using the CreateProcess API.
* If this option is not specified, IE is launched using IELaunchURL, if
* available. For IE 8 and above, this option requires the TabProcGrowth
* registry value to be set to 0.
*
* @param {boolean} force Whether to use the CreateProcess API.
* @return {!Options} A self reference.
*/
forceCreateProcessApi(force) {
this.options_[Key.FORCE_CREATE_PROCESS] = !!force;
return this;
}
/**
* Specifies command-line switches to use when launching Internet Explorer.
* This is only valid when used with {@link #forceCreateProcessApi}.
*
* @param {...(string|!Array.<string>)} var_args The arguments to add.
* @return {!Options} A self reference.
*/
addArguments(var_args) {
var args = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || [];
args = args.concat.apply(args, arguments);
this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = args;
return this;
}
/**
* Configures whether proxies should be configured on a per-process basis. If
* not set, setting a {@linkplain #setProxy proxy} will configure the system
* proxy. The default behavior is to use the system proxy.
*
* @param {boolean} enable Whether to enable per-process proxy settings.
* @return {!Options} A self reference.
*/
usePerProcessProxy(enable) {
this.options_[Key.USE_PER_PROCESS_PROXY] = !!enable;
return this;
}
/**
* Configures whether to clear the cache, cookies, history, and saved form data
* before starting the browser. _Using this capability will clear session data
* for all running instances of Internet Explorer, including those started
* manually._
*
* @param {boolean} cleanSession Whether to clear all session data on startup.
* @return {!Options} A self reference.
*/
ensureCleanSession(cleanSession) {
this.options_[Key.ENSURE_CLEAN_SESSION] = !!cleanSession;
return this;
}
/**
* Sets the path to the log file the driver should log to.
* @param {string} file The log file path.
* @return {!Options} A self reference.
*/
setLogFile(file) {
this.options_[Key.LOG_FILE] = file;
return this;
}
/**
* Sets the IEDriverServer's logging {@linkplain Level level}.
* @param {Level} level The logging level.
* @return {!Options} A self reference.
*/
setLogLevel(level) {
this.options_[Key.LOG_LEVEL] = level;
return this;
}
/**
* Sets the IP address of the driver's host adapter.
* @param {string} host The IP address to use.
* @return {!Options} A self reference.
*/
setHost(host) {
this.options_[Key.HOST] = host;
return this;
}
/**
* Sets the path of the temporary data directory to use.
* @param {string} path The log file path.
* @return {!Options} A self reference.
*/
setExtractPath(path) {
this.options_[Key.EXTRACT_PATH] = path;
return this;
}
/**
* Sets whether the driver should start in silent mode.
* @param {boolean} silent Whether to run in silent mode.
* @return {!Options} A self reference.
*/
silent(silent) {
this.options_[Key.SILENT] = silent;
return this;
}
/**
* Sets the proxy settings for the new session.
* @param {capabilities.ProxyConfig} proxy The proxy configuration to use.
* @return {!Options} A self reference.
*/
setProxy(proxy) {
this.proxy_ = proxy;
return this;
}
/**
* Converts this options instance to a {@link capabilities.Capabilities}
* object.
* @param {capabilities.Capabilities=} opt_capabilities The capabilities to
* merge these options into, if any.
* @return {!capabilities.Capabilities} The capabilities.
*/
toCapabilities(opt_capabilities) {
var caps = opt_capabilities || capabilities.Capabilities.ie();
if (this.proxy_) {
caps.set(capabilities.Capability.PROXY, this.proxy_);
}
Object.keys(this.options_).forEach(function(key) {
caps.set(key, this.options_[key]);
}, this);
return caps;
}
}
function createServiceFromCapabilities(capabilities) {
if (process.platform !== 'win32') {
throw Error(
'The IEDriver may only be used on Windows, but you appear to be on ' +
process.platform + '. Did you mean to run against a remote ' +
'WebDriver server?');
}
let exe = io.findInPath(IEDRIVER_EXE, true);
if (!exe || !fs.existsSync(exe)) {
throw Error(
`${IEDRIVER_EXE} could not be found on the current PATH. Please ` +
`download the latest version of ${IEDRIVER_EXE} from ` +
'http://selenium-release.storage.googleapis.com/index.html and ' +
'ensure it can be found on your system PATH.');
}
var args = [];
if (capabilities.has(Key.HOST)) {
args.push('--host=' + capabilities.get(Key.HOST));
}
if (capabilities.has(Key.LOG_FILE)) {
args.push('--log-file=' + capabilities.get(Key.LOG_FILE));
}
if (capabilities.has(Key.LOG_LEVEL)) {
args.push('--log-level=' + capabilities.get(Key.LOG_LEVEL));
}
if (capabilities.has(Key.EXTRACT_PATH)) {
args.push('--extract-path=' + capabilities.get(Key.EXTRACT_PATH));
}
if (capabilities.get(Key.SILENT)) {
args.push('--silent');
}
var port = portprober.findFreePort();
return new remote.DriverService(exe, {
loopback: true,
port: port,
args: port.then(function(port) {
return args.concat('--port=' + port);
}),
stdio: 'ignore'
});
}
/**
* A WebDriver client for Microsoft's Internet Explorer.
*/
class Driver extends webdriver.WebDriver {
/**
* Creates a new session for Microsoft's Internet Explorer.
*
* @param {(capabilities.Capabilities|Options)=} opt_config The configuration
* options.
* @param {promise.ControlFlow=} opt_flow The control flow to use,
* or {@code null} to use the currently active flow.
* @return {!Driver} A new driver instance.
*/
static createSession(opt_config, opt_flow) {
var caps = opt_config instanceof Options ?
opt_config.toCapabilities() :
(opt_config || capabilities.Capabilities.ie());
var service = createServiceFromCapabilities(caps);
var client = service.start().then(url => new http.HttpClient(url));
var executor = new http.Executor(client);
return /** @type {!Driver} */(super.createSession(
executor, caps, opt_flow, () => service.kill()));
}
/**
* This function is a no-op as file detectors are not supported by this
* implementation.
* @override
*/
setFileDetector() {}
}
// PUBLIC API
exports.Driver = Driver;
exports.Options = Options;
exports.Level = Level;

694
node_modules/selenium-webdriver/index.js generated vendored Normal file
View file

@ -0,0 +1,694 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview The main user facing module. Exports WebDriver's primary
* public API and provides convenience assessors to certain sub-modules.
*/
'use strict';
const chrome = require('./chrome');
const edge = require('./edge');
const firefox = require('./firefox');
const _http = require('./http');
const ie = require('./ie');
const actions = require('./lib/actions');
const by = require('./lib/by');
const capabilities = require('./lib/capabilities');
const command = require('./lib/command');
const error = require('./lib/error');
const events = require('./lib/events');
const input = require('./lib/input');
const logging = require('./lib/logging');
const promise = require('./lib/promise');
const session = require('./lib/session');
const until = require('./lib/until');
const webdriver = require('./lib/webdriver');
const opera = require('./opera');
const phantomjs = require('./phantomjs');
const remote = require('./remote');
const safari = require('./safari');
const Browser = capabilities.Browser;
const Capabilities = capabilities.Capabilities;
const Capability = capabilities.Capability;
const Session = session.Session;
const WebDriver = webdriver.WebDriver;
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
* address once started.
*/
function startSeleniumServer(jar) {
if (!seleniumServer) {
seleniumServer = new remote.SeleniumServer(jar);
}
return seleniumServer.start();
}
/**
* {@linkplain webdriver.WebDriver#setFileDetector WebDriver's setFileDetector}
* method uses a non-standard command to transfer files from the local client
* to the remote end hosting the browser. Many of the WebDriver sub-types, like
* the {@link chrome.Driver} and {@link firefox.Driver}, do not support this
* command. Thus, these classes override the `setFileDetector` to no-op.
*
* This function uses a mixin to re-enable `setFileDetector` by calling the
* original method on the WebDriver prototype directly. This is used only when
* the builder creates a Chrome or Firefox instance that communicates with a
* remote end (and thus, support for remote file detectors is unknown).
*
* @param {function(new: webdriver.WebDriver, ...?)} ctor
* @return {function(new: webdriver.WebDriver, ...?)}
*/
function ensureFileDetectorsAreEnabled(ctor) {
const mixin = class extends ctor {
/** @param {input.FileDetector} detector */
setFileDetector(detector) {
webdriver.WebDriver.prototype.setFileDetector.call(this, detector);
}
};
return mixin;
}
/**
* A thenable wrapper around a {@linkplain webdriver.IWebDriver IWebDriver}
* instance that allows commands to be issued directly instead of having to
* repeatedly call `then`:
*
* let driver = new Builder().build();
* driver.then(d => d.get(url)); // You can do this...
* driver.get(url); // ...or this
*
* If the driver instance fails to resolve (e.g. the session cannot be created),
* every issued command will fail.
*
* @extends {webdriver.IWebDriver}
* @extends {promise.CancellableThenable<!webdriver.IWebDriver>}
* @interface
*/
class ThenableWebDriver {
/** @param {...?} args */
static createSession(...args) {}
}
/**
* @const {!Map<function(new: WebDriver, !IThenable<!Session>, ...?),
* function(new: ThenableWebDriver, !IThenable<!Session>, ...?)>}
*/
const THENABLE_DRIVERS = new Map;
/**
* @param {function(new: WebDriver, !IThenable<!Session>, ...?)} ctor
* @param {...?} args
* @return {!ThenableWebDriver}
*/
function createDriver(ctor, ...args) {
let thenableWebDriverProxy = THENABLE_DRIVERS.get(ctor);
if (!thenableWebDriverProxy) {
/**
* @extends {WebDriver} // Needed since `ctor` is dynamically typed.
* @implements {ThenableWebDriver}
*/
thenableWebDriverProxy = class extends ctor {
/**
* @param {!IThenable<!Session>} session
* @param {...?} rest
*/
constructor(session, ...rest) {
super(session, ...rest);
const pd = this.getSession().then(session => {
return new ctor(session, ...rest);
});
/**
* @param {(string|Error)=} opt_reason
* @override
*/
this.cancel = function(opt_reason) {
if (promise.CancellableThenable.isImplementation(pd)) {
/** @type {!promise.CancellableThenable} */(pd).cancel(opt_reason);
}
};
/** @override */
this.then = pd.then.bind(pd);
/** @override */
this.catch = pd.then.bind(pd);
}
};
promise.CancellableThenable.addImplementation(thenableWebDriverProxy);
THENABLE_DRIVERS.set(ctor, thenableWebDriverProxy);
}
return thenableWebDriverProxy.createSession(...args);
}
/**
* Creates new {@link webdriver.WebDriver WebDriver} instances. The environment
* variables listed below may be used to override a builder's configuration,
* allowing quick runtime changes.
*
* - {@code SELENIUM_BROWSER}: defines the target browser in the form
* {@code browser[:version][:platform]}.
*
* - {@code SELENIUM_REMOTE_URL}: defines the remote URL for all builder
* instances. This environment variable should be set to a fully qualified
* URL for a WebDriver server (e.g. http://localhost:4444/wd/hub). This
* option always takes precedence over {@code SELENIUM_SERVER_JAR}.
*
* - {@code SELENIUM_SERVER_JAR}: defines the path to the
* <a href="http://selenium-release.storage.googleapis.com/index.html">
* standalone Selenium server</a> jar to use. The server will be started the
* first time a WebDriver instance and be killed when the process exits.
*
* Suppose you had mytest.js that created WebDriver with
*
* var driver = new webdriver.Builder()
* .forBrowser('chrome')
* .build();
*
* This test could be made to use Firefox on the local machine by running with
* `SELENIUM_BROWSER=firefox node mytest.js`. Rather than change the code to
* target Google Chrome on a remote machine, you can simply set the
* `SELENIUM_BROWSER` and `SELENIUM_REMOTE_URL` environment variables:
*
* SELENIUM_BROWSER=chrome:36:LINUX \
* SELENIUM_REMOTE_URL=http://www.example.com:4444/wd/hub \
* node mytest.js
*
* You could also use a local copy of the standalone Selenium server:
*
* SELENIUM_BROWSER=chrome:36:LINUX \
* SELENIUM_SERVER_JAR=/path/to/selenium-server-standalone.jar \
* node mytest.js
*/
class Builder {
constructor() {
/** @private @const */
this.log_ = logging.getLogger('webdriver.Builder');
/** @private {promise.ControlFlow} */
this.flow_ = null;
/** @private {string} */
this.url_ = '';
/** @private {?string} */
this.proxy_ = null;
/** @private {!Capabilities} */
this.capabilities_ = new Capabilities();
/** @private {chrome.Options} */
this.chromeOptions_ = null;
/** @private {firefox.Options} */
this.firefoxOptions_ = null;
/** @private {opera.Options} */
this.operaOptions_ = null;
/** @private {ie.Options} */
this.ieOptions_ = null;
/** @private {safari.Options} */
this.safariOptions_ = null;
/** @private {edge.Options} */
this.edgeOptions_ = null;
/** @private {boolean} */
this.ignoreEnv_ = false;
/** @private {http.Agent} */
this.agent_ = null;
}
/**
* Configures this builder to ignore any environment variable overrides and to
* only use the configuration specified through this instance's API.
*
* @return {!Builder} A self reference.
*/
disableEnvironmentOverrides() {
this.ignoreEnv_ = true;
return this;
}
/**
* Sets the URL of a remote WebDriver server to use. Once a remote URL has
* been specified, the builder direct all new clients to that server. If this
* method is never called, the Builder will attempt to create all clients
* locally.
*
* As an alternative to this method, you may also set the
* `SELENIUM_REMOTE_URL` environment variable.
*
* @param {string} url The URL of a remote server to use.
* @return {!Builder} A self reference.
*/
usingServer(url) {
this.url_ = url;
return this;
}
/**
* @return {string} The URL of the WebDriver server this instance is
* configured to use.
*/
getServerUrl() {
return this.url_;
}
/**
* Sets the URL of the proxy to use for the WebDriver's HTTP connections.
* If this method is never called, the Builder will create a connection
* without a proxy.
*
* @param {string} proxy The URL of a proxy to use.
* @return {!Builder} A self reference.
*/
usingWebDriverProxy(proxy) {
this.proxy_ = proxy;
return this;
}
/**
* @return {?string} The URL of the proxy server to use for the WebDriver's
* HTTP connections, or `null` if not set.
*/
getWebDriverProxy() {
return this.proxy_;
}
/**
* Sets the http agent to use for each request.
* If this method is not called, the Builder will use http.globalAgent by default.
*
* @param {http.Agent} agent The agent to use for each request.
* @return {!Builder} A self reference.
*/
usingHttpAgent(agent) {
this.agent_ = agent;
return this;
}
/**
* @return {http.Agent} The http agent used for each request
*/
getHttpAgent() {
return this.agent_;
}
/**
* Sets the desired capabilities when requesting a new session. This will
* overwrite any previously set capabilities.
* @param {!(Object|Capabilities)} capabilities The desired capabilities for
* a new session.
* @return {!Builder} A self reference.
*/
withCapabilities(capabilities) {
this.capabilities_ = new Capabilities(capabilities);
return this;
}
/**
* Returns the base set of capabilities this instance is currently configured
* to use.
* @return {!Capabilities} The current capabilities for this builder.
*/
getCapabilities() {
return this.capabilities_;
}
/**
* Configures the target browser for clients created by this instance.
* Any calls to {@link #withCapabilities} after this function will
* overwrite these settings.
*
* You may also define the target browser using the {@code SELENIUM_BROWSER}
* environment variable. If set, this environment variable should be of the
* form `browser[:[version][:platform]]`.
*
* @param {(string|Browser)} name The name of the target browser;
* common defaults are available on the {@link webdriver.Browser} enum.
* @param {string=} opt_version A desired version; may be omitted if any
* version should be used.
* @param {string=} opt_platform The desired platform; may be omitted if any
* version may be used.
* @return {!Builder} A self reference.
*/
forBrowser(name, opt_version, opt_platform) {
this.capabilities_.set(Capability.BROWSER_NAME, name);
this.capabilities_.set(Capability.VERSION, opt_version || null);
this.capabilities_.set(Capability.PLATFORM, opt_platform || null);
return this;
}
/**
* Sets the proxy configuration for the target browser.
* Any calls to {@link #withCapabilities} after this function will
* overwrite these settings.
*
* @param {!capabilities.ProxyConfig} config The configuration to use.
* @return {!Builder} A self reference.
*/
setProxy(config) {
this.capabilities_.setProxy(config);
return this;
}
/**
* Sets the logging preferences for the created session. Preferences may be
* changed by repeated calls, or by calling {@link #withCapabilities}.
* @param {!(./lib/logging.Preferences|Object<string, string>)} prefs The
* desired logging preferences.
* @return {!Builder} A self reference.
*/
setLoggingPrefs(prefs) {
this.capabilities_.setLoggingPrefs(prefs);
return this;
}
/**
* Sets whether native events should be used.
* @param {boolean} enabled Whether to enable native events.
* @return {!Builder} A self reference.
*/
setEnableNativeEvents(enabled) {
this.capabilities_.setEnableNativeEvents(enabled);
return this;
}
/**
* Sets how elements should be scrolled into view for interaction.
* @param {number} behavior The desired scroll behavior: either 0 to align
* with the top of the viewport or 1 to align with the bottom.
* @return {!Builder} A self reference.
*/
setScrollBehavior(behavior) {
this.capabilities_.setScrollBehavior(behavior);
return this;
}
/**
* Sets the default action to take with an unexpected alert before returning
* an error.
* @param {string} behavior The desired behavior; should be "accept",
* "dismiss", or "ignore". Defaults to "dismiss".
* @return {!Builder} A self reference.
*/
setAlertBehavior(behavior) {
this.capabilities_.setAlertBehavior(behavior);
return this;
}
/**
* Sets Chrome specific {@linkplain chrome.Options options} for drivers
* created by this builder. Any logging or proxy settings defined on the given
* options will take precedence over those set through
* {@link #setLoggingPrefs} and {@link #setProxy}, respectively.
*
* @param {!chrome.Options} options The ChromeDriver options to use.
* @return {!Builder} A self reference.
*/
setChromeOptions(options) {
this.chromeOptions_ = options;
return this;
}
/**
* Sets Firefox specific {@linkplain firefox.Options options} for drivers
* created by this builder. Any logging or proxy settings defined on the given
* options will take precedence over those set through
* {@link #setLoggingPrefs} and {@link #setProxy}, respectively.
*
* @param {!firefox.Options} options The FirefoxDriver options to use.
* @return {!Builder} A self reference.
*/
setFirefoxOptions(options) {
this.firefoxOptions_ = options;
return this;
}
/**
* @return {firefox.Options} the Firefox specific options currently configured
* for this instance.
*/
getFirefoxOptions() {
return this.firefoxOptions_;
}
/**
* Sets Opera specific {@linkplain opera.Options options} for drivers created
* by this builder. Any logging or proxy settings defined on the given options
* will take precedence over those set through {@link #setLoggingPrefs} and
* {@link #setProxy}, respectively.
*
* @param {!opera.Options} options The OperaDriver options to use.
* @return {!Builder} A self reference.
*/
setOperaOptions(options) {
this.operaOptions_ = options;
return this;
}
/**
* Set Internet Explorer specific {@linkplain ie.Options options} for drivers
* created by this builder. Any proxy settings defined on the given options
* will take precedence over those set through {@link #setProxy}.
*
* @param {!ie.Options} options The IEDriver options to use.
* @return {!Builder} A self reference.
*/
setIeOptions(options) {
this.ieOptions_ = options;
return this;
}
/**
* Set {@linkplain edge.Options options} specific to Microsoft's Edge browser
* for drivers created by this builder. Any proxy settings defined on the
* given options will take precedence over those set through
* {@link #setProxy}.
*
* @param {!edge.Options} options The MicrosoftEdgeDriver options to use.
* @return {!Builder} A self reference.
*/
setEdgeOptions(options) {
this.edgeOptions_ = options;
return this;
}
/**
* Sets Safari specific {@linkplain safari.Options options} for drivers
* created by this builder. Any logging settings defined on the given options
* will take precedence over those set through {@link #setLoggingPrefs}.
*
* @param {!safari.Options} options The Safari options to use.
* @return {!Builder} A self reference.
*/
setSafariOptions(options) {
this.safariOptions_ = options;
return this;
}
/**
* @return {safari.Options} the Safari specific options currently configured
* for this instance.
*/
getSafariOptions() {
return this.safariOptions_;
}
/**
* Sets the control flow that created drivers should execute actions in. If
* the flow is never set, or is set to {@code null}, it will use the active
* flow at the time {@link #build()} is called.
* @param {promise.ControlFlow} flow The control flow to use, or
* {@code null} to
* @return {!Builder} A self reference.
*/
setControlFlow(flow) {
this.flow_ = flow;
return this;
}
/**
* Creates a new WebDriver client based on this builder's current
* configuration.
*
* This method will return a {@linkplain ThenableWebDriver} instance, allowing
* users to issue commands directly without calling `then()`. The returned
* thenable wraps a promise that will resolve to a concrete
* {@linkplain webdriver.WebDriver WebDriver} instance. The promise will be
* rejected if the remote end fails to create a new session.
*
* @return {!ThenableWebDriver} A new WebDriver instance.
* @throws {Error} If the current configuration is invalid.
*/
build() {
// Create a copy for any changes we may need to make based on the current
// environment.
var capabilities = new Capabilities(this.capabilities_);
var browser;
if (!this.ignoreEnv_ && process.env.SELENIUM_BROWSER) {
this.log_.fine(`SELENIUM_BROWSER=${process.env.SELENIUM_BROWSER}`);
browser = process.env.SELENIUM_BROWSER.split(/:/, 3);
capabilities.set(Capability.BROWSER_NAME, browser[0]);
capabilities.set(Capability.VERSION, browser[1] || null);
capabilities.set(Capability.PLATFORM, browser[2] || null);
}
browser = capabilities.get(Capability.BROWSER_NAME);
if (typeof browser !== 'string') {
throw TypeError(
`Target browser must be a string, but is <${typeof browser}>;` +
' did you forget to call forBrowser()?');
}
if (browser === 'ie') {
browser = Browser.INTERNET_EXPLORER;
}
// Apply browser specific overrides.
if (browser === Browser.CHROME && this.chromeOptions_) {
capabilities.merge(this.chromeOptions_.toCapabilities());
} else if (browser === Browser.FIREFOX && this.firefoxOptions_) {
capabilities.merge(this.firefoxOptions_.toCapabilities());
} else if (browser === Browser.INTERNET_EXPLORER && this.ieOptions_) {
capabilities.merge(this.ieOptions_.toCapabilities());
} else if (browser === Browser.OPERA && this.operaOptions_) {
capabilities.merge(this.operaOptions_.toCapabilities());
} else if (browser === Browser.SAFARI && this.safariOptions_) {
capabilities.merge(this.safariOptions_.toCapabilities());
} else if (browser === Browser.EDGE && this.edgeOptions_) {
capabilities.merge(this.edgeOptions_.toCapabilities());
}
// Check for a remote browser.
let url = this.url_;
if (!this.ignoreEnv_) {
if (process.env.SELENIUM_REMOTE_URL) {
this.log_.fine(
`SELENIUM_REMOTE_URL=${process.env.SELENIUM_REMOTE_URL}`);
url = process.env.SELENIUM_REMOTE_URL;
} else if (process.env.SELENIUM_SERVER_JAR) {
this.log_.fine(
`SELENIUM_SERVER_JAR=${process.env.SELENIUM_SERVER_JAR}`);
url = startSeleniumServer(process.env.SELENIUM_SERVER_JAR);
}
}
if (url) {
this.log_.fine('Creating session on remote server');
let client = Promise.resolve(url)
.then(url => new _http.HttpClient(url, this.agent_, this.proxy_));
let executor = new _http.Executor(client);
if (browser === Browser.CHROME) {
const driver = ensureFileDetectorsAreEnabled(chrome.Driver);
return createDriver(
driver, capabilities, executor, this.flow_);
}
if (browser === Browser.FIREFOX) {
const driver = ensureFileDetectorsAreEnabled(firefox.Driver);
return createDriver(
driver, capabilities, executor, this.flow_);
}
return createDriver(
WebDriver, executor, capabilities, this.flow_);
}
// Check for a native browser.
switch (browser) {
case Browser.CHROME:
return createDriver(chrome.Driver, capabilities, null, this.flow_);
case Browser.FIREFOX:
return createDriver(firefox.Driver, capabilities, null, this.flow_);
case Browser.INTERNET_EXPLORER:
return createDriver(ie.Driver, capabilities, this.flow_);
case Browser.EDGE:
return createDriver(edge.Driver, capabilities, null, this.flow_);
case Browser.OPERA:
return createDriver(opera.Driver, capabilities, null, this.flow_);
case Browser.PHANTOM_JS:
return createDriver(phantomjs.Driver, capabilities, this.flow_);
case Browser.SAFARI:
return createDriver(safari.Driver, capabilities, this.flow_);
default:
throw new Error('Do not know how to build driver: ' + browser
+ '; did you forget to call usingServer(url)?');
}
}
}
// PUBLIC API
exports.ActionSequence = actions.ActionSequence;
exports.Browser = capabilities.Browser;
exports.Builder = Builder;
exports.Button = input.Button;
exports.By = by.By;
exports.Capabilities = capabilities.Capabilities;
exports.Capability = capabilities.Capability;
exports.Condition = webdriver.Condition;
exports.EventEmitter = events.EventEmitter;
exports.FileDetector = input.FileDetector;
exports.Key = input.Key;
exports.Session = session.Session;
exports.ThenableWebDriver = ThenableWebDriver;
exports.TouchSequence = actions.TouchSequence;
exports.WebDriver = webdriver.WebDriver;
exports.WebElement = webdriver.WebElement;
exports.WebElementCondition = webdriver.WebElementCondition;
exports.WebElementPromise = webdriver.WebElementPromise;
exports.error = error;
exports.logging = logging;
exports.promise = promise;
exports.until = until;

153
node_modules/selenium-webdriver/io/exec.js generated vendored Normal file
View file

@ -0,0 +1,153 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
const childProcess = require('child_process');
/**
* A hash with configuration options for an executed command.
*
* - `args` - Command line arguments.
* - `env` - Command environment; will inherit from the current process if
* missing.
* - `stdio` - IO configuration for the spawned server process. For more
* information, refer to the documentation of `child_process.spawn`.
*
* @typedef {{
* args: (!Array<string>|undefined),
* env: (!Object<string, string>|undefined),
* stdio: (string|!Array<string|number|!stream.Stream|null|undefined>|
* undefined)
* }}
*/
var Options;
/**
* Describes a command's termination conditions.
*/
class Result {
/**
* @param {?number} code The exit code, or {@code null} if the command did not
* exit normally.
* @param {?string} signal The signal used to kill the command, or
* {@code null}.
*/
constructor(code, signal) {
/** @type {?number} */
this.code = code;
/** @type {?string} */
this.signal = signal;
}
/** @override */
toString() {
return `Result(code=${this.code}, signal=${this.signal})`;
}
}
const COMMAND_RESULT = /** !WeakMap<!Command, !Promise<!Result>> */new WeakMap;
const KILL_HOOK = /** !WeakMap<!Command, function(string)> */new WeakMap;
/**
* Represents a command running in a sub-process.
*/
class Command {
/**
* @param {!Promise<!Result>} result The command result.
* @param {function(string)} onKill The function to call when {@link #kill()}
* is called.
*/
constructor(result, onKill) {
COMMAND_RESULT.set(this, result);
KILL_HOOK.set(this, onKill);
}
/**
* @return {!Promise<!Result>} A promise for the result of this
* command.
*/
result() {
return /** @type {!Promise<!Result>} */(COMMAND_RESULT.get(this));
}
/**
* Sends a signal to the underlying process.
* @param {string=} opt_signal The signal to send; defaults to `SIGTERM`.
*/
kill(opt_signal) {
KILL_HOOK.get(this)(opt_signal || 'SIGTERM');
}
}
// PUBLIC API
/**
* Spawns a child process. The returned {@link Command} may be used to wait
* for the process result or to send signals to the process.
*
* @param {string} command The executable to spawn.
* @param {Options=} opt_options The command options.
* @return {!Command} The launched command.
*/
module.exports = function exec(command, opt_options) {
var options = opt_options || {};
var proc = childProcess.spawn(command, options.args || [], {
env: options.env || process.env,
stdio: options.stdio || 'ignore'
});
// This process should not wait on the spawned child, however, we do
// want to ensure the child is killed when this process exits.
proc.unref();
process.once('exit', onProcessExit);
let result = new Promise(resolve => {
proc.once('exit', (code, signal) => {
proc = null;
process.removeListener('exit', onProcessExit);
resolve(new Result(code, signal));
});
});
return new Command(result, killCommand);
function onProcessExit() {
killCommand('SIGTERM');
}
function killCommand(signal) {
process.removeListener('exit', onProcessExit);
if (proc) {
proc.kill(signal);
proc = null;
}
}
};
// Exported to improve generated API documentation.
module.exports.Command = Command;
/** @typedef {!Options} */
module.exports.Options = Options;
module.exports.Result = Result;

359
node_modules/selenium-webdriver/io/index.js generated vendored Normal file
View file

@ -0,0 +1,359 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
var fs = require('fs'),
path = require('path'),
rimraf = require('rimraf'),
tmp = require('tmp');
/**
* @param {!Function} fn .
* @return {!Promise<T>} .
* @template T
*/
function checkedCall(fn) {
return new Promise((resolve, reject) => {
try {
fn((err, value) => {
if (err) {
reject(err);
} else {
resolve(value);
}
});
} catch (e) {
reject(e);
}
});
}
// PUBLIC API
/**
* Recursively removes a directory and all of its contents. This is equivalent
* to {@code rm -rf} on a POSIX system.
* @param {string} dirPath Path to the directory to remove.
* @return {!Promise} A promise to be resolved when the operation has
* completed.
*/
exports.rmDir = function(dirPath) {
return new Promise(function(fulfill, reject) {
var numAttempts = 0;
attemptRm();
function attemptRm() {
numAttempts += 1;
rimraf(dirPath, function(err) {
if (err) {
if (err.code && err.code === 'ENOTEMPTY' && numAttempts < 2) {
attemptRm();
return;
}
reject(err);
} else {
fulfill();
}
});
}
});
};
/**
* Copies one file to another.
* @param {string} src The source file.
* @param {string} dst The destination file.
* @return {!Promise<string>} A promise for the copied file's path.
*/
exports.copy = function(src, dst) {
return new Promise(function(fulfill, reject) {
var rs = fs.createReadStream(src);
rs.on('error', reject);
rs.on('end', () => fulfill(dst));
var ws = fs.createWriteStream(dst);
ws.on('error', reject);
rs.pipe(ws);
});
};
/**
* Recursively copies the contents of one directory to another.
* @param {string} src The source directory to copy.
* @param {string} dst The directory to copy into.
* @param {(RegExp|function(string): boolean)=} opt_exclude An exclusion filter
* as either a regex or predicate function. All files matching this filter
* will not be copied.
* @return {!Promise<string>} A promise for the destination
* directory's path once all files have been copied.
*/
exports.copyDir = function(src, dst, opt_exclude) {
var predicate = opt_exclude;
if (opt_exclude && typeof opt_exclude !== 'function') {
predicate = function(p) {
return !opt_exclude.test(p);
};
}
// TODO(jleyba): Make this function completely async.
if (!fs.existsSync(dst)) {
fs.mkdirSync(dst);
}
var files = fs.readdirSync(src);
files = files.map(function(file) {
return path.join(src, file);
});
if (predicate) {
files = files.filter(/** @type {function(string): boolean} */(predicate));
}
var results = [];
files.forEach(function(file) {
var stats = fs.statSync(file);
var target = path.join(dst, path.basename(file));
if (stats.isDirectory()) {
if (!fs.existsSync(target)) {
fs.mkdirSync(target, stats.mode);
}
results.push(exports.copyDir(file, target, predicate));
} else {
results.push(exports.copy(file, target));
}
});
return Promise.all(results).then(() => dst);
};
/**
* Tests if a file path exists.
* @param {string} aPath The path to test.
* @return {!Promise<boolean>} A promise for whether the file exists.
*/
exports.exists = function(aPath) {
return new Promise(function(fulfill, reject) {
let type = typeof aPath;
if (type !== 'string') {
reject(TypeError(`expected string path, but got ${type}`));
} else {
fs.exists(aPath, fulfill);
}
});
};
/**
* Calls `stat(2)`.
* @param {string} aPath The path to stat.
* @return {!Promise<!fs.Stats>} A promise for the file stats.
*/
exports.stat = function stat(aPath) {
return checkedCall(callback => fs.stat(aPath, callback));
};
/**
* Deletes a name from the filesystem and possibly the file it refers to. Has
* no effect if the file does not exist.
* @param {string} aPath The path to remove.
* @return {!Promise} A promise for when the file has been removed.
*/
exports.unlink = function(aPath) {
return new Promise(function(fulfill, reject) {
fs.exists(aPath, function(exists) {
if (exists) {
fs.unlink(aPath, function(err) {
err && reject(err) || fulfill();
});
} else {
fulfill();
}
});
});
};
/**
* @return {!Promise<string>} A promise for the path to a temporary directory.
* @see https://www.npmjs.org/package/tmp
*/
exports.tmpDir = function() {
return checkedCall(tmp.dir);
};
/**
* @param {{postfix: string}=} opt_options Temporary file options.
* @return {!Promise<string>} A promise for the path to a temporary file.
* @see https://www.npmjs.org/package/tmp
*/
exports.tmpFile = function(opt_options) {
return checkedCall(callback => {
// |tmp.file| checks arguments length to detect options rather than doing a
// truthy check, so we must only pass options if there are some to pass.
if (opt_options) {
tmp.file(opt_options, callback);
} else {
tmp.file(callback);
}
});
};
/**
* Searches the {@code PATH} environment variable for the given file.
* @param {string} file The file to locate on the PATH.
* @param {boolean=} opt_checkCwd Whether to always start with the search with
* the current working directory, regardless of whether it is explicitly
* listed on the PATH.
* @return {?string} Path to the located file, or {@code null} if it could
* not be found.
*/
exports.findInPath = function(file, opt_checkCwd) {
let dirs = [];
if (opt_checkCwd) {
dirs.push(process.cwd());
}
dirs.push.apply(dirs, process.env['PATH'].split(path.delimiter));
let foundInDir = dirs.find(dir => {
let tmp = path.join(dir, file);
try {
let stats = fs.statSync(tmp);
return stats.isFile() && !stats.isDirectory();
} catch (ex) {
return false;
}
});
return foundInDir ? path.join(foundInDir, file) : null;
};
/**
* Reads the contents of the given file.
*
* @param {string} aPath Path to the file to read.
* @return {!Promise<!Buffer>} A promise that will resolve with a buffer of the
* file contents.
*/
exports.read = function(aPath) {
return checkedCall(callback => fs.readFile(aPath, callback));
};
/**
* Writes to a file.
*
* @param {string} aPath Path to the file to write to.
* @param {(string|!Buffer)} data The data to write.
* @return {!Promise} A promise that will resolve when the operation has
* completed.
*/
exports.write = function(aPath, data) {
return checkedCall(callback => fs.writeFile(aPath, data, callback));
};
/**
* Creates a directory.
*
* @param {string} aPath The directory path.
* @return {!Promise<string>} A promise that will resolve with the path of the
* created directory.
*/
exports.mkdir = function(aPath) {
return checkedCall(callback => {
fs.mkdir(aPath, undefined, err => {
if (err && err.code !== 'EEXIST') {
callback(err);
} else {
callback(null, aPath);
}
});
});
};
/**
* Recursively creates a directory and any ancestors that do not yet exist.
*
* @param {string} dir The directory path to create.
* @return {!Promise<string>} A promise that will resolve with the path of the
* created directory.
*/
exports.mkdirp = function mkdirp(dir) {
return checkedCall(callback => {
fs.mkdir(dir, undefined, err => {
if (!err) {
callback(null, dir);
return;
}
switch (err.code) {
case 'EEXIST':
callback(null, dir);
return;
case 'ENOENT':
return mkdirp(path.dirname(dir))
.then(() => mkdirp(dir))
.then(() => callback(null, dir), err => callback(err));
default:
callback(err);
return;
}
});
});
};
/**
* Recursively walks a directory, returning a promise that will resolve with
* a list of all files/directories seen.
*
* @param {string} rootPath the directory to walk.
* @return {!Promise<!Array<{path: string, dir: boolean}>>} a promise that will
* resolve with a list of entries seen. For each entry, the recorded path
* will be relative to `rootPath`.
*/
exports.walkDir = function(rootPath) {
let seen = [];
return (function walk(dir) {
return checkedCall(callback => fs.readdir(dir, callback))
.then(files => Promise.all(files.map(file => {
file = path.join(dir, file);
return checkedCall(cb => fs.stat(file, cb)).then(stats => {
seen.push({
path: path.relative(rootPath, file),
dir: stats.isDirectory()
});
return stats.isDirectory() && walk(file);
});
})));
})(rootPath).then(() => seen);
};

5
node_modules/selenium-webdriver/lib/README generated vendored Normal file
View file

@ -0,0 +1,5 @@
This directory contains modules internal to selenium-webdriver that are not
intended for general consumption. They may change at any time.
All files in this directory and the atoms/ subdirectory may only depend on
built-in JavaScript features and other modules in this directory.

604
node_modules/selenium-webdriver/lib/actions.js generated vendored Normal file
View file

@ -0,0 +1,604 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
const command = require('./command');
const error = require('./error');
const input = require('./input');
/**
* @param {!IArrayLike} args .
* @return {!Array} .
*/
function flatten(args) {
let result = [];
for (let i = 0; i < args.length; i++) {
let element = args[i];
if (Array.isArray(element)) {
result.push.apply(result, flatten(element));
} else {
result.push(element);
}
}
return result;
}
const MODIFIER_KEYS = new Set([
input.Key.ALT,
input.Key.CONTROL,
input.Key.SHIFT,
input.Key.COMMAND
]);
/**
* Checks that a key is a modifier key.
* @param {!input.Key} key The key to check.
* @throws {error.InvalidArgumentError} If the key is not a modifier key.
* @private
*/
function checkModifierKey(key) {
if (!MODIFIER_KEYS.has(key)) {
throw new error.InvalidArgumentError('Not a modifier key');
}
}
/**
* Class for defining sequences of complex user interactions. Each sequence
* will not be executed until {@link #perform} is called.
*
* This class should not be instantiated directly. Instead, obtain an instance
* using {@link ./webdriver.WebDriver#actions() WebDriver.actions()}.
*
* Sample usage:
*
* driver.actions().
* keyDown(Key.SHIFT).
* click(element1).
* click(element2).
* dragAndDrop(element3, element4).
* keyUp(Key.SHIFT).
* perform();
*
*/
class ActionSequence {
/**
* @param {!./webdriver.WebDriver} driver The driver that should be used to
* perform this action sequence.
*/
constructor(driver) {
/** @private {!./webdriver.WebDriver} */
this.driver_ = driver;
/** @private {!Array<{description: string, command: !command.Command}>} */
this.actions_ = [];
}
/**
* Schedules an action to be executed each time {@link #perform} is called on
* this instance.
*
* @param {string} description A description of the command.
* @param {!command.Command} command The command.
* @private
*/
schedule_(description, command) {
this.actions_.push({
description: description,
command: command
});
}
/**
* Executes this action sequence.
*
* @return {!./promise.Thenable} A promise that will be resolved once
* this sequence has completed.
*/
perform() {
// Make a protected copy of the scheduled actions. This will protect against
// users defining additional commands before this sequence is actually
// executed.
let actions = this.actions_.concat();
let driver = this.driver_;
return driver.controlFlow().execute(function() {
let results = actions.map(action => {
return driver.schedule(action.command, action.description);
});
return Promise.all(results);
}, 'ActionSequence.perform');
}
/**
* 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).
*
* @param {(!./webdriver.WebElement|{x: number, y: number})} location The
* location to drag to, as either another WebElement or an offset in
* pixels.
* @param {{x: number, y: number}=} opt_offset If the target {@code location}
* is defined as a {@link ./webdriver.WebElement}, this parameter defines
* an offset within that element. The offset should be specified in pixels
* relative to the top-left corner of the element's bounding box. If
* omitted, the element's center will be used as the target offset.
* @return {!ActionSequence} A self reference.
*/
mouseMove(location, opt_offset) {
let cmd = new command.Command(command.Name.MOVE_TO);
if (typeof location.x === 'number') {
setOffset(/** @type {{x: number, y: number}} */(location));
} else {
cmd.setParameter('element', location.getId());
if (opt_offset) {
setOffset(opt_offset);
}
}
this.schedule_('mouseMove', cmd);
return this;
/** @param {{x: number, y: number}} offset The offset to use. */
function setOffset(offset) {
cmd.setParameter('xoffset', offset.x || 0);
cmd.setParameter('yoffset', offset.y || 0);
}
}
/**
* Schedules a mouse action.
* @param {string} description A simple descriptive label for the scheduled
* action.
* @param {!command.Name} commandName The name of the command.
* @param {(./webdriver.WebElement|input.Button)=} opt_elementOrButton Either
* the element to interact with or the button to click with.
* Defaults to {@link input.Button.LEFT} if neither an element nor
* button is specified.
* @param {input.Button=} opt_button The button to use. Defaults to
* {@link input.Button.LEFT}. Ignored if the previous argument is
* provided as a button.
* @return {!ActionSequence} A self reference.
* @private
*/
scheduleMouseAction_(
description, commandName, opt_elementOrButton, opt_button) {
let button;
if (typeof opt_elementOrButton === 'number') {
button = opt_elementOrButton;
} else {
if (opt_elementOrButton) {
this.mouseMove(
/** @type {!./webdriver.WebElement} */ (opt_elementOrButton));
}
button = opt_button !== void(0) ? opt_button : input.Button.LEFT;
}
let cmd = new command.Command(commandName).
setParameter('button', button);
this.schedule_(description, cmd);
return this;
}
/**
* Presses a mouse button. The mouse button will not be released until
* {@link #mouseUp} is called, regardless of whether that call is made in this
* sequence or another. The behavior for out-of-order events (e.g. mouseDown,
* click) is undefined.
*
* If an element is provided, the mouse will first be moved to the center
* of that element. This is equivalent to:
*
* sequence.mouseMove(element).mouseDown()
*
* Warning: this method currently only supports the left mouse button. See
* [issue 4047](http://code.google.com/p/selenium/issues/detail?id=4047).
*
* @param {(./webdriver.WebElement|input.Button)=} opt_elementOrButton Either
* the element to interact with or the button to click with.
* Defaults to {@link input.Button.LEFT} if neither an element nor
* button is specified.
* @param {input.Button=} opt_button The button to use. Defaults to
* {@link input.Button.LEFT}. Ignored if a button is provided as the
* first argument.
* @return {!ActionSequence} A self reference.
*/
mouseDown(opt_elementOrButton, opt_button) {
return this.scheduleMouseAction_('mouseDown',
command.Name.MOUSE_DOWN, opt_elementOrButton, opt_button);
}
/**
* Releases a mouse button. Behavior is undefined for calling this function
* without a previous call to {@link #mouseDown}.
*
* If an element is provided, the mouse will first be moved to the center
* of that element. This is equivalent to:
*
* sequence.mouseMove(element).mouseUp()
*
* Warning: this method currently only supports the left mouse button. See
* [issue 4047](http://code.google.com/p/selenium/issues/detail?id=4047).
*
* @param {(./webdriver.WebElement|input.Button)=} opt_elementOrButton Either
* the element to interact with or the button to click with.
* Defaults to {@link input.Button.LEFT} if neither an element nor
* button is specified.
* @param {input.Button=} opt_button The button to use. Defaults to
* {@link input.Button.LEFT}. Ignored if a button is provided as the
* first argument.
* @return {!ActionSequence} A self reference.
*/
mouseUp(opt_elementOrButton, opt_button) {
return this.scheduleMouseAction_('mouseUp',
command.Name.MOUSE_UP, opt_elementOrButton, opt_button);
}
/**
* Convenience function for performing a "drag and drop" manuever. The target
* element may be moved to the location of another element, or by an offset (in
* pixels).
*
* @param {!./webdriver.WebElement} element The element to drag.
* @param {(!./webdriver.WebElement|{x: number, y: number})} location The
* location to drag to, either as another WebElement or an offset in
* pixels.
* @return {!ActionSequence} A self reference.
*/
dragAndDrop(element, location) {
return this.mouseDown(element).mouseMove(location).mouseUp();
}
/**
* Clicks a mouse button.
*
* If an element is provided, the mouse will first be moved to the center
* of that element. This is equivalent to:
*
* sequence.mouseMove(element).click()
*
* @param {(./webdriver.WebElement|input.Button)=} opt_elementOrButton Either
* the element to interact with or the button to click with.
* Defaults to {@link input.Button.LEFT} if neither an element nor
* button is specified.
* @param {input.Button=} opt_button The button to use. Defaults to
* {@link input.Button.LEFT}. Ignored if a button is provided as the
* first argument.
* @return {!ActionSequence} A self reference.
*/
click(opt_elementOrButton, opt_button) {
return this.scheduleMouseAction_('click',
command.Name.CLICK, opt_elementOrButton, opt_button);
}
/**
* Double-clicks a mouse button.
*
* If an element is provided, the mouse will first be moved to the center of
* that element. This is equivalent to:
*
* sequence.mouseMove(element).doubleClick()
*
* Warning: this method currently only supports the left mouse button. See
* [issue 4047](http://code.google.com/p/selenium/issues/detail?id=4047).
*
* @param {(./webdriver.WebElement|input.Button)=} opt_elementOrButton Either
* the element to interact with or the button to click with.
* Defaults to {@link input.Button.LEFT} if neither an element nor
* button is specified.
* @param {input.Button=} opt_button The button to use. Defaults to
* {@link input.Button.LEFT}. Ignored if a button is provided as the
* first argument.
* @return {!ActionSequence} A self reference.
*/
doubleClick(opt_elementOrButton, opt_button) {
return this.scheduleMouseAction_('doubleClick',
command.Name.DOUBLE_CLICK, opt_elementOrButton, opt_button);
}
/**
* Schedules a keyboard action.
*
* @param {string} description A simple descriptive label for the scheduled
* action.
* @param {!Array<(string|!input.Key)>} keys The keys to send.
* @return {!ActionSequence} A self reference.
* @private
*/
scheduleKeyboardAction_(description, keys) {
let cmd = new command.Command(command.Name.SEND_KEYS_TO_ACTIVE_ELEMENT)
.setParameter('value', keys);
this.schedule_(description, cmd);
return this;
}
/**
* 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
* targeted at the currently focused element.
*
* @param {!input.Key} key The modifier key to push. Must be one of
* {ALT, CONTROL, SHIFT, COMMAND, META}.
* @return {!ActionSequence} A self reference.
* @throws {error.InvalidArgumentError} If the key is not a valid modifier
* key.
*/
keyDown(key) {
checkModifierKey(key);
return this.scheduleKeyboardAction_('keyDown', [key]);
}
/**
* 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}.
* @return {!ActionSequence} A self reference.
* @throws {error.InvalidArgumentError} If the key is not a valid modifier
* key.
*/
keyUp(key) {
checkModifierKey(key);
return this.scheduleKeyboardAction_('keyUp', [key]);
}
/**
* 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 targeted at the currently focused element.
*
* @param {...(string|!input.Key|!Array<(string|!input.Key)>)} var_args
* The keys to type.
* @return {!ActionSequence} A self reference.
* @throws {Error} If the key is not a valid modifier key.
*/
sendKeys(var_args) {
let keys = flatten(arguments);
return this.scheduleKeyboardAction_('sendKeys', keys);
}
}
/**
* Class for defining sequences of user touch interactions. Each sequence
* will not be executed until {@link #perform} is called.
*
* This class should not be instantiated directly. Instead, obtain an instance
* using {@link ./webdriver.WebDriver#touchActions() WebDriver.touchActions()}.
*
* Sample usage:
*
* driver.touchActions().
* tapAndHold({x: 0, y: 0}).
* move({x: 3, y: 4}).
* release({x: 10, y: 10}).
* perform();
*
*/
class TouchSequence {
/**
* @param {!./webdriver.WebDriver} driver The driver that should be used to
* perform this action sequence.
*/
constructor(driver) {
/** @private {!./webdriver.WebDriver} */
this.driver_ = driver;
/** @private {!Array<{description: string, command: !command.Command}>} */
this.actions_ = [];
}
/**
* Schedules an action to be executed each time {@link #perform} is called on
* this instance.
* @param {string} description A description of the command.
* @param {!command.Command} command The command.
* @private
*/
schedule_(description, command) {
this.actions_.push({
description: description,
command: command
});
}
/**
* Executes this action sequence.
* @return {!./promise.Thenable} A promise that will be resolved once
* this sequence has completed.
*/
perform() {
// Make a protected copy of the scheduled actions. This will protect against
// users defining additional commands before this sequence is actually
// executed.
let actions = this.actions_.concat();
let driver = this.driver_;
return driver.controlFlow().execute(function() {
let results = actions.map(action => {
return driver.schedule(action.command, action.description);
});
return Promise.all(results);
}, 'TouchSequence.perform');
}
/**
* Taps an element.
*
* @param {!./webdriver.WebElement} elem The element to tap.
* @return {!TouchSequence} A self reference.
*/
tap(elem) {
let cmd = new command.Command(command.Name.TOUCH_SINGLE_TAP).
setParameter('element', elem.getId());
this.schedule_('tap', cmd);
return this;
}
/**
* Double taps an element.
*
* @param {!./webdriver.WebElement} elem The element to double tap.
* @return {!TouchSequence} A self reference.
*/
doubleTap(elem) {
let cmd = new command.Command(command.Name.TOUCH_DOUBLE_TAP).
setParameter('element', elem.getId());
this.schedule_('doubleTap', cmd);
return this;
}
/**
* Long press on an element.
*
* @param {!./webdriver.WebElement} elem The element to long press.
* @return {!TouchSequence} A self reference.
*/
longPress(elem) {
let cmd = new command.Command(command.Name.TOUCH_LONG_PRESS).
setParameter('element', elem.getId());
this.schedule_('longPress', cmd);
return this;
}
/**
* Touch down at the given location.
*
* @param {{x: number, y: number}} location The location to touch down at.
* @return {!TouchSequence} A self reference.
*/
tapAndHold(location) {
let cmd = new command.Command(command.Name.TOUCH_DOWN).
setParameter('x', location.x).
setParameter('y', location.y);
this.schedule_('tapAndHold', cmd);
return this;
}
/**
* Move a held {@linkplain #tapAndHold touch} to the specified location.
*
* @param {{x: number, y: number}} location The location to move to.
* @return {!TouchSequence} A self reference.
*/
move(location) {
let cmd = new command.Command(command.Name.TOUCH_MOVE).
setParameter('x', location.x).
setParameter('y', location.y);
this.schedule_('move', cmd);
return this;
}
/**
* Release a held {@linkplain #tapAndHold touch} at the specified location.
*
* @param {{x: number, y: number}} location The location to release at.
* @return {!TouchSequence} A self reference.
*/
release(location) {
let cmd = new command.Command(command.Name.TOUCH_UP).
setParameter('x', location.x).
setParameter('y', location.y);
this.schedule_('release', cmd);
return this;
}
/**
* Scrolls the touch screen by the given offset.
*
* @param {{x: number, y: number}} offset The offset to scroll to.
* @return {!TouchSequence} A self reference.
*/
scroll(offset) {
let cmd = new command.Command(command.Name.TOUCH_SCROLL).
setParameter('xoffset', offset.x).
setParameter('yoffset', offset.y);
this.schedule_('scroll', cmd);
return this;
}
/**
* Scrolls the touch screen, starting on `elem` and moving by the specified
* offset.
*
* @param {!./webdriver.WebElement} elem The element where scroll starts.
* @param {{x: number, y: number}} offset The offset to scroll to.
* @return {!TouchSequence} A self reference.
*/
scrollFromElement(elem, offset) {
let cmd = new command.Command(command.Name.TOUCH_SCROLL).
setParameter('element', elem.getId()).
setParameter('xoffset', offset.x).
setParameter('yoffset', offset.y);
this.schedule_('scrollFromElement', cmd);
return this;
}
/**
* Flick, starting anywhere on the screen, at speed xspeed and yspeed.
*
* @param {{xspeed: number, yspeed: number}} speed The speed to flick in each
direction, in pixels per second.
* @return {!TouchSequence} A self reference.
*/
flick(speed) {
let cmd = new command.Command(command.Name.TOUCH_FLICK).
setParameter('xspeed', speed.xspeed).
setParameter('yspeed', speed.yspeed);
this.schedule_('flick', cmd);
return this;
}
/**
* Flick starting at elem and moving by x and y at specified speed.
*
* @param {!./webdriver.WebElement} elem The element where flick starts.
* @param {{x: number, y: number}} offset The offset to flick to.
* @param {number} speed The speed to flick at in pixels per second.
* @return {!TouchSequence} A self reference.
*/
flickElement(elem, offset, speed) {
let cmd = new command.Command(command.Name.TOUCH_FLICK).
setParameter('element', elem.getId()).
setParameter('xoffset', offset.x).
setParameter('yoffset', offset.y).
setParameter('speed', speed);
this.schedule_('flickElement', cmd);
return this;
}
}
// PUBLIC API
module.exports = {
ActionSequence: ActionSequence,
TouchSequence: TouchSequence,
};

285
node_modules/selenium-webdriver/lib/by.js generated vendored Normal file
View file

@ -0,0 +1,285 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* @fileoverview Factory methods for the supported locator strategies.
*/
/**
* Short-hand expressions for the primary element locator strategies.
* For example the following two statements are equivalent:
*
* var e1 = driver.findElement(By.id('foo'));
* var e2 = driver.findElement({id: 'foo'});
*
* Care should be taken when using JavaScript minifiers (such as the
* Closure compiler), as locator hashes will always be parsed using
* the un-obfuscated properties listed.
*
* @typedef {(
* {className: string}|
* {css: string}|
* {id: string}|
* {js: string}|
* {linkText: string}|
* {name: string}|
* {partialLinkText: string}|
* {tagName: string}|
* {xpath: string})}
*/
var ByHash;
/**
* Error thrown if an invalid character is encountered while escaping a CSS
* identifier.
* @see https://drafts.csswg.org/cssom/#serialize-an-identifier
*/
class InvalidCharacterError extends Error {
constructor() {
super();
this.name = this.constructor.name;
}
}
/**
* Escapes a CSS string.
* @param {string} css the string to escape.
* @return {string} the escaped string.
* @throws {TypeError} if the input value is not a string.
* @throws {InvalidCharacterError} if the string contains an invalid character.
* @see https://drafts.csswg.org/cssom/#serialize-an-identifier
*/
function escapeCss(css) {
if (typeof css !== 'string') {
throw new TypeError('input must be a string');
}
let ret = '';
const n = css.length;
for (let i = 0; i < n; i++) {
const c = css.charCodeAt(i);
if (c == 0x0) {
throw new InvalidCharacterError();
}
if ((c >= 0x0001 && c <= 0x001F)
|| c == 0x007F
|| (i == 0 && c >= 0x0030 && c <= 0x0039)
|| (i == 1 && c >= 0x0030 && c <= 0x0039
&& css.charCodeAt(0) == 0x002D)) {
ret += '\\' + c.toString(16) + ' ';
continue;
}
if (i == 0 && c == 0x002D && n == 1) {
ret += '\\' + css.charAt(i);
continue;
}
if (c >= 0x0080
|| c == 0x002D // -
|| c == 0x005F // _
|| (c >= 0x0030 && c <= 0x0039) // [0-9]
|| (c >= 0x0041 && c <= 0x005A) // [A-Z]
|| (c >= 0x0061 && c <= 0x007A)) { // [a-z]
ret += css.charAt(i);
continue;
}
ret += '\\' + css.charAt(i);
}
return ret;
}
/**
* Describes a mechanism for locating an element on the page.
* @final
*/
class By {
/**
* @param {string} using the name of the location strategy to use.
* @param {string} value the value to search for.
*/
constructor(using, value) {
/** @type {string} */
this.using = using;
/** @type {string} */
this.value = value;
}
/**
* Locates elements that have a specific class name.
*
* @param {string} name The class name to search for.
* @return {!By} The new locator.
* @see http://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
* @see http://www.w3.org/TR/CSS2/selector.html#class-html
*/
static className(name) {
let names = name.split(/\s+/g)
.filter(s => s.length > 0)
.map(s => escapeCss(s));
return By.css('.' + names.join('.'));
}
/**
* Locates elements using a CSS selector.
*
* @param {string} selector The CSS selector to use.
* @return {!By} The new locator.
* @see http://www.w3.org/TR/CSS2/selector.html
*/
static css(selector) {
return new By('css selector', 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.
* @return {!By} The new locator.
*/
static id(id) {
return By.css('*[id="' + escapeCss(id) + '"]');
}
/**
* Locates link elements whose
* {@linkplain webdriver.WebElement#getText visible text} matches the given
* string.
*
* @param {string} text The link text to search for.
* @return {!By} The new locator.
*/
static linkText(text) {
return new By('link text', text);
}
/**
* Locates an elements by evaluating a
* {@linkplain webdriver.WebDriver#executeScript JavaScript expression}.
* The result of this expression must be an element or list of elements.
*
* @param {!(string|Function)} script The script to execute.
* @param {...*} var_args The arguments to pass to the script.
* @return {function(!./webdriver.WebDriver): !./promise.Promise}
* A new JavaScript-based locator function.
*/
static js(script, var_args) {
let args = Array.prototype.slice.call(arguments, 0);
return function(driver) {
return driver.executeScript.apply(driver, args);
};
}
/**
* Locates elements whose `name` attribute has the given value.
*
* @param {string} name The name attribute to search for.
* @return {!By} The new locator.
*/
static name(name) {
return By.css('*[name="' + escapeCss(name) + '"]');
}
/**
* Locates link elements whose
* {@linkplain webdriver.WebElement#getText visible text} contains the given
* substring.
*
* @param {string} text The substring to check for in a link's visible text.
* @return {!By} The new locator.
*/
static partialLinkText(text) {
return new By('partial link text', text);
}
/**
* Locates elements with a given tag name.
*
* @param {string} name The tag name to search for.
* @return {!By} The new locator.
* @deprecated Use {@link By.css() By.css(tagName)} instead.
*/
static tagName(name) {
return By.css(name);
}
/**
* Locates elements matching a XPath selector. Care should be taken when
* using an XPath selector with a {@link webdriver.WebElement} as WebDriver
* will respect the context in the specified in the selector. For example,
* given the selector `//div`, WebDriver will search from the document root
* regardless of whether the locator was used with a WebElement.
*
* @param {string} xpath The XPath selector to use.
* @return {!By} The new locator.
* @see http://www.w3.org/TR/xpath/
*/
static xpath(xpath) {
return new By('xpath', xpath);
}
/** @override */
toString() {
// The static By.name() overrides this.constructor.name. Shame...
return `By(${this.using}, ${this.value})`;
}
}
/**
* Checks if a value is a valid locator.
* @param {!(By|Function|ByHash)} locator The value to check.
* @return {!(By|Function)} The valid locator.
* @throws {TypeError} If the given value does not define a valid locator
* strategy.
*/
function check(locator) {
if (locator instanceof By || typeof locator === 'function') {
return locator;
}
if (locator
&& typeof locator === 'object'
&& typeof locator.using === 'string'
&& typeof locator.value === 'string') {
return new By(locator.using, locator.value);
}
for (let key in locator) {
if (locator.hasOwnProperty(key) && By.hasOwnProperty(key)) {
return By[key](locator[key]);
}
}
throw new TypeError('Invalid locator');
}
// PUBLIC API
module.exports = {
By: By,
checkedLocator: check,
};

489
node_modules/selenium-webdriver/lib/capabilities.js generated vendored Normal file
View file

@ -0,0 +1,489 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* @fileoverview Defines types related to describing the capabilities of a
* WebDriver session.
*/
const Symbols = require('./symbols');
/**
* Recognized browser names.
* @enum {string}
*/
const Browser = {
ANDROID: 'android',
CHROME: 'chrome',
EDGE: 'MicrosoftEdge',
FIREFOX: 'firefox',
IE: 'internet explorer',
INTERNET_EXPLORER: 'internet explorer',
IPAD: 'iPad',
IPHONE: 'iPhone',
OPERA: 'opera',
PHANTOM_JS: 'phantomjs',
SAFARI: 'safari',
HTMLUNIT: 'htmlunit'
};
/**
* Common Capability keys.
* @enum {string}
*/
const Capability = {
/**
* Indicates whether a driver should accept all SSL certs by default. This
* capability only applies when requesting a new session. To query whether
* a driver can handle insecure SSL certs, see {@link #SECURE_SSL}.
*/
ACCEPT_SSL_CERTS: 'acceptSslCerts',
/**
* The browser name. Common browser names are defined in the {@link Browser}
* enum.
*/
BROWSER_NAME: 'browserName',
/**
* Defines how elements should be scrolled into the viewport for interaction.
* This capability will be set to zero (0) if elements are aligned with the
* top of the viewport, or one (1) if aligned with the bottom. The default
* behavior is to align with the top of the viewport.
*/
ELEMENT_SCROLL_BEHAVIOR: 'elementScrollBehavior',
/**
* Whether the driver is capable of handling modal alerts (e.g. alert,
* confirm, prompt). To define how a driver <i>should</i> handle alerts,
* use {@link #UNEXPECTED_ALERT_BEHAVIOR}.
*/
HANDLES_ALERTS: 'handlesAlerts',
/**
* Key for the logging driver logging preferences.
*/
LOGGING_PREFS: 'loggingPrefs',
/**
* Whether this session generates native events when simulating user input.
*/
NATIVE_EVENTS: 'nativeEvents',
/**
* Describes the platform the browser is running on. Will be one of
* ANDROID, IOS, LINUX, MAC, UNIX, or WINDOWS. When <i>requesting</i> a
* session, ANY may be used to indicate no platform preference (this is
* semantically equivalent to omitting the platform capability).
*/
PLATFORM: 'platform',
/**
* Describes the proxy configuration to use for a new WebDriver session.
*/
PROXY: 'proxy',
/** Whether the driver supports changing the browser's orientation. */
ROTATABLE: 'rotatable',
/**
* Whether a driver is only capable of handling secure SSL certs. To request
* that a driver accept insecure SSL certs by default, use
* {@link #ACCEPT_SSL_CERTS}.
*/
SECURE_SSL: 'secureSsl',
/** Whether the driver supports manipulating the app cache. */
SUPPORTS_APPLICATION_CACHE: 'applicationCacheEnabled',
/** Whether the driver supports locating elements with CSS selectors. */
SUPPORTS_CSS_SELECTORS: 'cssSelectorsEnabled',
/** Whether the browser supports JavaScript. */
SUPPORTS_JAVASCRIPT: 'javascriptEnabled',
/** Whether the driver supports controlling the browser's location info. */
SUPPORTS_LOCATION_CONTEXT: 'locationContextEnabled',
/** Whether the driver supports taking screenshots. */
TAKES_SCREENSHOT: 'takesScreenshot',
/**
* Defines how the driver should handle unexpected alerts. The value should
* be one of "accept", "dismiss", or "ignore".
*/
UNEXPECTED_ALERT_BEHAVIOR: 'unexpectedAlertBehaviour',
/** Defines the browser version. */
VERSION: 'version'
};
/**
* Describes how a proxy should be configured for a WebDriver session.
* @record
*/
function ProxyConfig() {}
/**
* The proxy type. Must be one of {"manual", "pac", "system"}.
* @type {string}
*/
ProxyConfig.prototype.proxyType;
/**
* URL for the PAC file to use. Only used if {@link #proxyType} is "pac".
* @type {(string|undefined)}
*/
ProxyConfig.prototype.proxyAutoconfigUrl;
/**
* The proxy host for FTP requests. Only used if {@link #proxyType} is "manual".
* @type {(string|undefined)}
*/
ProxyConfig.prototype.ftpProxy;
/**
* The proxy host for HTTP requests. Only used if {@link #proxyType} is
* "manual".
* @type {(string|undefined)}
*/
ProxyConfig.prototype.httpProxy;
/**
* The proxy host for HTTPS requests. Only used if {@link #proxyType} is
* "manual".
* @type {(string|undefined)}
*/
ProxyConfig.prototype.sslProxy;
/**
* A comma delimited list of hosts which should bypass all proxies. Only used if
* {@link #proxyType} is "manual".
* @type {(string|undefined)}
*/
ProxyConfig.prototype.noProxy;
/**
* Converts a generic hash object to a map.
* @param {!Object<string, ?>} hash The hash object.
* @return {!Map<string, ?>} The converted map.
*/
function toMap(hash) {
let m = new Map;
for (let key in hash) {
if (hash.hasOwnProperty(key)) {
m.set(key, hash[key]);
}
}
return m;
}
/**
* Describes a set of capabilities for a WebDriver session.
*/
class Capabilities {
/**
* @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
* capabilities to initialize this instance from.
*/
constructor(other = undefined) {
if (other instanceof Capabilities) {
other = other.map_;
} else if (other && !(other instanceof Map)) {
other = toMap(other);
}
/** @private @const {!Map<string, ?>} */
this.map_ = new Map(other);
}
/**
* @return {!Capabilities} A basic set of capabilities for Android.
*/
static android() {
return new Capabilities()
.set(Capability.BROWSER_NAME, Browser.ANDROID);
}
/**
* @return {!Capabilities} A basic set of capabilities for Chrome.
*/
static chrome() {
return new Capabilities().set(Capability.BROWSER_NAME, Browser.CHROME);
}
/**
* @return {!Capabilities} A basic set of capabilities for Microsoft Edge.
*/
static edge() {
return new Capabilities()
.set(Capability.BROWSER_NAME, Browser.EDGE);
}
/**
* @return {!Capabilities} A basic set of capabilities for Firefox.
*/
static firefox() {
return new Capabilities().set(Capability.BROWSER_NAME, Browser.FIREFOX);
}
/**
* @return {!Capabilities} A basic set of capabilities for Internet Explorer.
*/
static ie() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.INTERNET_EXPLORER);
}
/**
* @return {!Capabilities} A basic set of capabilities for iPad.
*/
static ipad() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.IPAD);
}
/**
* @return {!Capabilities} A basic set of capabilities for iPhone.
*/
static iphone() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.IPHONE);
}
/**
* @return {!Capabilities} A basic set of capabilities for Opera.
*/
static opera() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.OPERA);
}
/**
* @return {!Capabilities} A basic set of capabilities for PhantomJS.
*/
static phantomjs() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.PHANTOM_JS);
}
/**
* @return {!Capabilities} A basic set of capabilities for Safari.
*/
static safari() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.SAFARI);
}
/**
* @return {!Capabilities} A basic set of capabilities for HTMLUnit.
*/
static htmlunit() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.HTMLUNIT);
}
/**
* @return {!Capabilities} A basic set of capabilities for HTMLUnit
* with enabled Javascript.
*/
static htmlunitwithjs() {
return new Capabilities().
set(Capability.BROWSER_NAME, Browser.HTMLUNIT).
set(Capability.SUPPORTS_JAVASCRIPT, true);
}
/**
* @return {!Object<string, ?>} The JSON representation of this instance.
* Note, the returned object may contain nested promised values.
* @suppress {checkTypes} Suppress [] access on a struct (state inherited from
* Map).
*/
[Symbols.serialize]() {
return serialize(this);
}
/**
* @param {string} key the parameter key to get.
* @return {T} the stored parameter value.
* @template T
*/
get(key) {
return this.map_.get(key);
}
/**
* @param {string} key the key to test.
* @return {boolean} whether this capability set has the specified key.
*/
has(key) {
return this.map_.has(key);
}
/**
* @return {!Iterator<string>} an iterator of the keys set.
*/
keys() {
return this.map_.keys();
}
/** @return {number} The number of capabilities set. */
get size() {
return this.map_.size;
}
/**
* Merges another set of capabilities into this instance.
* @param {!(Capabilities|Map<String, ?>|Object<string, ?>)} other The other
* set of capabilities to merge.
* @return {!Capabilities} A self reference.
*/
merge(other) {
if (!other) {
throw new TypeError('no capabilities provided for merge');
}
let map;
if (other instanceof Capabilities) {
map = other.map_;
} else if (other instanceof Map) {
map = other;
} else {
other = toMap(other);
}
for (let key of other.keys()) {
this.set(key, other.get(key));
}
return this;
}
/**
* Deletes an entry from this set of capabilities.
*
* @param {string} key the capability key to delete.
*/
delete(key) {
this.map_.delete(key);
}
/**
* @param {string} key The capability key.
* @param {*} value The capability value.
* @return {!Capabilities} A self reference.
* @throws {TypeError} If the `key` is not a string.
*/
set(key, value) {
if (typeof key !== 'string') {
throw new TypeError('Capability keys must be strings: ' + typeof key);
}
this.map_.set(key, value);
return this;
}
/**
* Sets the logging preferences. Preferences may be specified as a
* {@link ./logging.Preferences} instance, or as a map of log-type to
* log-level.
* @param {!(./logging.Preferences|Object<string>)} prefs The logging
* preferences.
* @return {!Capabilities} A self reference.
*/
setLoggingPrefs(prefs) {
return this.set(Capability.LOGGING_PREFS, prefs);
}
/**
* Sets the proxy configuration for this instance.
* @param {ProxyConfig} proxy The desired proxy configuration.
* @return {!Capabilities} A self reference.
*/
setProxy(proxy) {
return this.set(Capability.PROXY, proxy);
}
/**
* Sets whether native events should be used.
* @param {boolean} enabled Whether to enable native events.
* @return {!Capabilities} A self reference.
*/
setEnableNativeEvents(enabled) {
return this.set(Capability.NATIVE_EVENTS, enabled);
}
/**
* Sets how elements should be scrolled into view for interaction.
* @param {number} behavior The desired scroll behavior: either 0 to align
* with the top of the viewport or 1 to align with the bottom.
* @return {!Capabilities} A self reference.
*/
setScrollBehavior(behavior) {
return this.set(Capability.ELEMENT_SCROLL_BEHAVIOR, behavior);
}
/**
* Sets the default action to take with an unexpected alert before returning
* an error.
* @param {string} behavior The desired behavior should be "accept",
* "dismiss", or "ignore". Defaults to "dismiss".
* @return {!Capabilities} A self reference.
*/
setAlertBehavior(behavior) {
return this.set(Capability.UNEXPECTED_ALERT_BEHAVIOR, behavior);
}
}
/**
* Serializes a capabilities object. This is defined as a standalone function
* so it may be type checked (where Capabilities[Symbols.serialize] has type
* checking disabled since it is defined with [] access on a struct).
*
* @param {!Capabilities} caps The capabilities to serialize.
* @return {!Object<string, ?>} The JSON representation of this instance.
* Note, the returned object may contain nested promised values.
*/
function serialize(caps) {
let ret = {};
for (let key of caps.keys()) {
let cap = caps.get(key);
if (cap !== undefined && cap !== null) {
ret[key] = cap;
}
}
return ret;
}
// PUBLIC API
module.exports = {
Browser: Browser,
Capabilities: Capabilities,
Capability: Capability,
ProxyConfig: ProxyConfig
};

245
node_modules/selenium-webdriver/lib/command.js generated vendored Normal file
View file

@ -0,0 +1,245 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Contains several classes for handling commands.
*/
'use strict';
/**
* Describes a command to execute.
* @final
*/
class Command {
/** @param {string} name The name of this command. */
constructor(name) {
/** @private {string} */
this.name_ = name;
/** @private {!Object<*>} */
this.parameters_ = {};
}
/** @return {string} This command's name. */
getName() {
return this.name_;
}
/**
* Sets a parameter to send with this command.
* @param {string} name The parameter name.
* @param {*} value The parameter value.
* @return {!Command} A self reference.
*/
setParameter(name, value) {
this.parameters_[name] = value;
return this;
}
/**
* Sets the parameters for this command.
* @param {!Object<*>} parameters The command parameters.
* @return {!Command} A self reference.
*/
setParameters(parameters) {
this.parameters_ = parameters;
return this;
}
/**
* Returns a named command parameter.
* @param {string} key The parameter key to look up.
* @return {*} The parameter value, or undefined if it has not been set.
*/
getParameter(key) {
return this.parameters_[key];
}
/**
* @return {!Object<*>} The parameters to send with this command.
*/
getParameters() {
return this.parameters_;
}
}
/**
* Enumeration of predefined names command names that all command processors
* will support.
* @enum {string}
*/
// TODO: Delete obsolete command names.
const Name = {
GET_SERVER_STATUS: 'getStatus',
NEW_SESSION: 'newSession',
GET_SESSIONS: 'getSessions',
DESCRIBE_SESSION: 'getSessionCapabilities',
CLOSE: 'close',
QUIT: 'quit',
GET_CURRENT_URL: 'getCurrentUrl',
GET: 'get',
GO_BACK: 'goBack',
GO_FORWARD: 'goForward',
REFRESH: 'refresh',
ADD_COOKIE: 'addCookie',
GET_COOKIE: 'getCookie',
GET_ALL_COOKIES: 'getCookies',
DELETE_COOKIE: 'deleteCookie',
DELETE_ALL_COOKIES: 'deleteAllCookies',
GET_ACTIVE_ELEMENT: 'getActiveElement',
FIND_ELEMENT: 'findElement',
FIND_ELEMENTS: 'findElements',
FIND_CHILD_ELEMENT: 'findChildElement',
FIND_CHILD_ELEMENTS: 'findChildElements',
CLEAR_ELEMENT: 'clearElement',
CLICK_ELEMENT: 'clickElement',
SEND_KEYS_TO_ELEMENT: 'sendKeysToElement',
SUBMIT_ELEMENT: 'submitElement',
GET_CURRENT_WINDOW_HANDLE: 'getCurrentWindowHandle',
GET_WINDOW_HANDLES: 'getWindowHandles',
GET_WINDOW_POSITION: 'getWindowPosition',
SET_WINDOW_POSITION: 'setWindowPosition',
GET_WINDOW_SIZE: 'getWindowSize',
SET_WINDOW_SIZE: 'setWindowSize',
MAXIMIZE_WINDOW: 'maximizeWindow',
SWITCH_TO_WINDOW: 'switchToWindow',
SWITCH_TO_FRAME: 'switchToFrame',
GET_PAGE_SOURCE: 'getPageSource',
GET_TITLE: 'getTitle',
EXECUTE_SCRIPT: 'executeScript',
EXECUTE_ASYNC_SCRIPT: 'executeAsyncScript',
GET_ELEMENT_TEXT: 'getElementText',
GET_ELEMENT_TAG_NAME: 'getElementTagName',
IS_ELEMENT_SELECTED: 'isElementSelected',
IS_ELEMENT_ENABLED: 'isElementEnabled',
IS_ELEMENT_DISPLAYED: 'isElementDisplayed',
GET_ELEMENT_LOCATION: 'getElementLocation',
GET_ELEMENT_LOCATION_IN_VIEW: 'getElementLocationOnceScrolledIntoView',
GET_ELEMENT_SIZE: 'getElementSize',
GET_ELEMENT_ATTRIBUTE: 'getElementAttribute',
GET_ELEMENT_VALUE_OF_CSS_PROPERTY: 'getElementValueOfCssProperty',
ELEMENT_EQUALS: 'elementEquals',
SCREENSHOT: 'screenshot',
TAKE_ELEMENT_SCREENSHOT: 'takeElementScreenshot',
IMPLICITLY_WAIT: 'implicitlyWait',
SET_SCRIPT_TIMEOUT: 'setScriptTimeout',
GET_TIMEOUT: 'getTimeout',
SET_TIMEOUT: 'setTimeout',
ACCEPT_ALERT: 'acceptAlert',
DISMISS_ALERT: 'dismissAlert',
GET_ALERT_TEXT: 'getAlertText',
SET_ALERT_TEXT: 'setAlertValue',
SET_ALERT_CREDENTIALS: 'setAlertCredentials',
EXECUTE_SQL: 'executeSQL',
GET_LOCATION: 'getLocation',
SET_LOCATION: 'setLocation',
GET_APP_CACHE: 'getAppCache',
GET_APP_CACHE_STATUS: 'getStatus',
CLEAR_APP_CACHE: 'clearAppCache',
IS_BROWSER_ONLINE: 'isBrowserOnline',
SET_BROWSER_ONLINE: 'setBrowserOnline',
GET_LOCAL_STORAGE_ITEM: 'getLocalStorageItem',
GET_LOCAL_STORAGE_KEYS: 'getLocalStorageKeys',
SET_LOCAL_STORAGE_ITEM: 'setLocalStorageItem',
REMOVE_LOCAL_STORAGE_ITEM: 'removeLocalStorageItem',
CLEAR_LOCAL_STORAGE: 'clearLocalStorage',
GET_LOCAL_STORAGE_SIZE: 'getLocalStorageSize',
GET_SESSION_STORAGE_ITEM: 'getSessionStorageItem',
GET_SESSION_STORAGE_KEYS: 'getSessionStorageKey',
SET_SESSION_STORAGE_ITEM: 'setSessionStorageItem',
REMOVE_SESSION_STORAGE_ITEM: 'removeSessionStorageItem',
CLEAR_SESSION_STORAGE: 'clearSessionStorage',
GET_SESSION_STORAGE_SIZE: 'getSessionStorageSize',
SET_SCREEN_ORIENTATION: 'setScreenOrientation',
GET_SCREEN_ORIENTATION: 'getScreenOrientation',
// These belong to the Advanced user interactions - an element is
// optional for these commands.
CLICK: 'mouseClick',
DOUBLE_CLICK: 'mouseDoubleClick',
MOUSE_DOWN: 'mouseButtonDown',
MOUSE_UP: 'mouseButtonUp',
MOVE_TO: 'mouseMoveTo',
SEND_KEYS_TO_ACTIVE_ELEMENT: 'sendKeysToActiveElement',
// These belong to the Advanced Touch API
TOUCH_SINGLE_TAP: 'touchSingleTap',
TOUCH_DOWN: 'touchDown',
TOUCH_UP: 'touchUp',
TOUCH_MOVE: 'touchMove',
TOUCH_SCROLL: 'touchScroll',
TOUCH_DOUBLE_TAP: 'touchDoubleTap',
TOUCH_LONG_PRESS: 'touchLongPress',
TOUCH_FLICK: 'touchFlick',
GET_AVAILABLE_LOG_TYPES: 'getAvailableLogTypes',
GET_LOG: 'getLog',
GET_SESSION_LOGS: 'getSessionLogs',
// Non-standard commands used by the standalone Selenium server.
UPLOAD_FILE: 'uploadFile'
};
/**
* Handles the execution of WebDriver {@link Command commands}.
* @interface
*/
class Executor {
/**
* Executes the given {@code command}. If there is an error executing the
* command, the provided callback will be invoked with the offending error.
* Otherwise, the callback will be invoked with a null Error and non-null
* response object.
*
* @param {!Command} command The command to execute.
* @return {!Promise<?>} A promise that will be fulfilled with the command
* result.
*/
execute(command) {}
}
// PUBLIC API
module.exports = {
Command: Command,
Name: Name,
Executor: Executor
};

34
node_modules/selenium-webdriver/lib/devmode.js generated vendored Normal file
View file

@ -0,0 +1,34 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Module used to detect if scripts are loaded from the Selenium
* project repo instead of from a deployed package.
*/
'use strict';
const fs = require('fs');
const path = require('path');
/**
* @const {boolean}
*/
module.exports = (function() {
let buildDescFile = path.join(__dirname, '..', '..', 'build.desc');
return fs.existsSync(buildDescFile);
})();

210
node_modules/selenium-webdriver/lib/events.js generated vendored Normal file
View file

@ -0,0 +1,210 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* Describes an event listener registered on an {@linkplain EventEmitter}.
*/
class Listener {
/**
* @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.
*/
constructor(fn, scope, oneshot) {
this.fn = fn;
this.scope = scope;
this.oneshot = oneshot;
}
}
/** @type {!WeakMap<!EventEmitter, !Map<string, !Set<!Listener>>>} */
const EVENTS = new WeakMap;
/**
* Object that can emit events for others to listen for.
*/
class EventEmitter {
/**
* Fires an event and calls all listeners.
* @param {string} type The type of event to emit.
* @param {...*} var_args Any arguments to pass to each listener.
*/
emit(type, var_args) {
let events = EVENTS.get(this);
if (!events) {
return;
}
let args = Array.prototype.slice.call(arguments, 1);
let listeners = events.get(type);
if (listeners) {
for (let listener of listeners) {
listener.fn.apply(listener.scope, args);
if (listener.oneshot) {
listeners.delete(listener);
}
}
}
}
/**
* Returns a mutable list of listeners for a specific type of event.
* @param {string} type The type of event to retrieve the listeners for.
* @return {!Set<!Listener>} The registered listeners for the given event
* type.
*/
listeners(type) {
let events = EVENTS.get(this);
if (!events) {
events = new Map;
EVENTS.set(this, events);
}
let listeners = events.get(type);
if (!listeners) {
listeners = new Set;
events.set(type, listeners);
}
return listeners;
}
/**
* Registers a listener.
* @param {string} type The type of event to listen for.
* @param {!Function} fn The function to invoke when the event is fired.
* @param {Object=} opt_self The object in whose scope to invoke the listener.
* @param {boolean=} opt_oneshot Whether the listener should b (e removed after
* the first event is fired.
* @return {!EventEmitter} A self reference.
* @private
*/
addListener_(type, fn, opt_self, opt_oneshot) {
let listeners = this.listeners(type);
for (let listener of listeners) {
if (listener.fn === fn) {
return this;
}
}
listeners.add(new Listener(fn, opt_self || undefined, !!opt_oneshot));
return this;
}
/**
* Registers a listener.
* @param {string} type The type of event to listen for.
* @param {!Function} fn The function to invoke when the event is fired.
* @param {Object=} opt_self The object in whose scope to invoke the listener.
* @return {!EventEmitter} A self reference.
*/
addListener(type, fn, opt_self) {
return this.addListener_(type, fn, opt_self, false);
}
/**
* Registers a one-time listener which will be called only the first time an
* event is emitted, after which it will be removed.
* @param {string} type The type of event to listen for.
* @param {!Function} fn The function to invoke when the event is fired.
* @param {Object=} opt_self The object in whose scope to invoke the listener.
* @return {!EventEmitter} A self reference.
*/
once(type, fn, opt_self) {
return this.addListener_(type, fn, opt_self, true);
}
/**
* An alias for {@link #addListener() addListener()}.
* @param {string} type The type of event to listen for.
* @param {!Function} fn The function to invoke when the event is fired.
* @param {Object=} opt_self The object in whose scope to invoke the listener.
* @return {!EventEmitter} A self reference.
*/
on(type, fn, opt_self) {
return this.addListener(type, fn, opt_self);
}
/**
* Removes a previously registered event listener.
* @param {string} type The type of event to unregister.
* @param {!Function} listenerFn The handler function to remove.
* @return {!EventEmitter} A self reference.
*/
removeListener(type, listenerFn) {
if (typeof type !== 'string' || typeof listenerFn !== 'function') {
throw TypeError('invalid args: expected (string, function), got ('
+ (typeof type) + ', ' + (typeof listenerFn) + ')');
}
let events = EVENTS.get(this);
if (!events) {
return this;
}
let listeners = events.get(type);
if (!listeners) {
return this;
}
let match;
for (let listener of listeners) {
if (listener.fn === listenerFn) {
match = listener;
break;
}
}
if (match) {
listeners.delete(match);
if (!listeners.size) {
events.delete(type);
}
}
return this;
}
/**
* Removes all listeners for a specific type of event. If no event is
* specified, all listeners across all types will be removed.
* @param {string=} opt_type The type of event to remove listeners from.
* @return {!EventEmitter} A self reference.
*/
removeAllListeners(opt_type) {
let events = EVENTS.get(this);
if (events) {
if (typeof opt_type === 'string') {
events.delete(opt_type);
} else {
EVENTS.delete(this);
}
}
return this;
}
}
// PUBLIC API
module.exports = {
EventEmitter: EventEmitter,
Listener: Listener
};

171
node_modules/selenium-webdriver/lib/input.js generated vendored Normal file
View file

@ -0,0 +1,171 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* @fileoverview Defines types related to user input with the WebDriver API.
*/
/**
* Enumeration of the buttons used in the advanced interactions API.
* @enum {number}
*/
const Button = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2
};
/**
* Representations of pressable keys that aren't text. These are stored in
* the Unicode PUA (Private Use Area) code points, 0xE000-0xF8FF. Refer to
* http://www.google.com.au/search?&q=unicode+pua&btnG=Search
*
* @enum {string}
*/
const Key = {
NULL: '\uE000',
CANCEL: '\uE001', // ^break
HELP: '\uE002',
BACK_SPACE: '\uE003',
TAB: '\uE004',
CLEAR: '\uE005',
RETURN: '\uE006',
ENTER: '\uE007',
SHIFT: '\uE008',
CONTROL: '\uE009',
ALT: '\uE00A',
PAUSE: '\uE00B',
ESCAPE: '\uE00C',
SPACE: '\uE00D',
PAGE_UP: '\uE00E',
PAGE_DOWN: '\uE00F',
END: '\uE010',
HOME: '\uE011',
ARROW_LEFT: '\uE012',
LEFT: '\uE012',
ARROW_UP: '\uE013',
UP: '\uE013',
ARROW_RIGHT: '\uE014',
RIGHT: '\uE014',
ARROW_DOWN: '\uE015',
DOWN: '\uE015',
INSERT: '\uE016',
DELETE: '\uE017',
SEMICOLON: '\uE018',
EQUALS: '\uE019',
NUMPAD0: '\uE01A', // number pad keys
NUMPAD1: '\uE01B',
NUMPAD2: '\uE01C',
NUMPAD3: '\uE01D',
NUMPAD4: '\uE01E',
NUMPAD5: '\uE01F',
NUMPAD6: '\uE020',
NUMPAD7: '\uE021',
NUMPAD8: '\uE022',
NUMPAD9: '\uE023',
MULTIPLY: '\uE024',
ADD: '\uE025',
SEPARATOR: '\uE026',
SUBTRACT: '\uE027',
DECIMAL: '\uE028',
DIVIDE: '\uE029',
F1: '\uE031', // function keys
F2: '\uE032',
F3: '\uE033',
F4: '\uE034',
F5: '\uE035',
F6: '\uE036',
F7: '\uE037',
F8: '\uE038',
F9: '\uE039',
F10: '\uE03A',
F11: '\uE03B',
F12: '\uE03C',
COMMAND: '\uE03D', // Apple command key
META: '\uE03D' // alias for Windows key
};
/**
* Simulate pressing many keys at once in a "chord". Takes a sequence of
* {@linkplain Key keys} or strings, appends each of the values to a string,
* adds the chord termination key ({@link Key.NULL}) and returns the resulting
* string.
*
* Note: when the low-level webdriver key handlers see Keys.NULL, active
* modifier keys (CTRL/ALT/SHIFT/etc) release via a keyup event.
*
* @param {...string} var_args The key sequence to concatenate.
* @return {string} The null-terminated key sequence.
*/
Key.chord = function(var_args) {
return Array.prototype.slice.call(arguments, 0).join('') + Key.NULL;
};
/**
* Used with {@link ./webelement.WebElement#sendKeys WebElement#sendKeys} on
* file input elements (`<input type="file">`) to detect when the entered key
* sequence defines the path to a file.
*
* By default, {@linkplain ./webelement.WebElement WebElement's} will enter all
* key sequences exactly as entered. You may set a
* {@linkplain ./webdriver.WebDriver#setFileDetector file detector} on the
* parent WebDriver instance to define custom behavior for handling file
* elements. Of particular note is the
* {@link selenium-webdriver/remote.FileDetector}, which should be used when
* running against a remote
* [Selenium Server](http://docs.seleniumhq.org/download/).
*/
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, 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
* for custom tailored file handling.
*
* @param {!./webdriver.WebDriver} driver The driver for the current browser.
* @param {string} path The path to process.
* @return {!Promise<string>} A promise for the processed file path.
* @package
*/
handleFile(driver, path) {
return Promise.resolve(path);
}
}
// PUBLIC API
module.exports = {
Button: Button,
Key: Key,
FileDetector: FileDetector
};

676
node_modules/selenium-webdriver/lib/logging.js generated vendored Normal file
View file

@ -0,0 +1,676 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* @fileoverview Defines WebDriver's logging system. The logging system is
* broken into major components: local and remote logging.
*
* The local logging API, which is anchored by the {@linkplain Logger} class is
* similar to Java's logging API. Loggers, retrieved by
* {@linkplain #getLogger getLogger(name)}, use hierarchical, dot-delimited
* namespaces (e.g. "" > "webdriver" > "webdriver.logging"). Recorded log
* messages are represented by the {@linkplain Entry} class. You can capture log
* records by {@linkplain Logger#addHandler attaching} a handler function to the
* desired logger. For convenience, you can quickly enable logging to the
* console by simply calling {@linkplain #installConsoleHandler
* installConsoleHandler}.
*
* The [remote logging API](https://github.com/SeleniumHQ/selenium/wiki/Logging)
* allows you to retrieve logs from a remote WebDriver server. This API uses the
* {@link Preferences} class to define desired log levels prior to creating
* a WebDriver session:
*
* var prefs = new logging.Preferences();
* prefs.setLevel(logging.Type.BROWSER, logging.Level.DEBUG);
*
* var caps = Capabilities.chrome();
* caps.setLoggingPrefs(prefs);
* // ...
*
* Remote log entries, also represented by the {@link Entry} class, may be
* retrieved via {@link webdriver.WebDriver.Logs}:
*
* driver.manage().logs().get(logging.Type.BROWSER)
* .then(function(entries) {
* entries.forEach(function(entry) {
* console.log('[%s] %s', entry.level.name, entry.message);
* });
* });
*
* **NOTE:** Only a few browsers support the remote logging API (notably
* Firefox and Chrome). Firefox supports basic logging functionality, while
* Chrome exposes robust
* [performance logging](https://sites.google.com/a/chromium.org/chromedriver/logging)
* options. Remote logging is still considered a non-standard feature, and the
* APIs exposed by this module for it are non-frozen. This module will be
* updated, possibly breaking backwards-compatibility, once logging is
* officially defined by the
* [W3C WebDriver spec](http://www.w3.org/TR/webdriver/).
*/
/**
* Defines a message level that may be used to control logging output.
*
* @final
*/
class Level {
/**
* @param {string} name the level's name.
* @param {number} level the level's numeric value.
*/
constructor(name, level) {
if (level < 0) {
throw new TypeError('Level must be >= 0');
}
/** @private {string} */
this.name_ = name;
/** @private {number} */
this.value_ = level;
}
/** This logger's name. */
get name() {
return this.name_;
}
/** The numeric log level. */
get value() {
return this.value_;
}
/** @override */
toString() {
return this.name;
}
}
/**
* Indicates no log messages should be recorded.
* @const
*/
Level.OFF = new Level('OFF', Infinity);
/**
* Log messages with a level of `1000` or higher.
* @const
*/
Level.SEVERE = new Level('SEVERE', 1000);
/**
* Log messages with a level of `900` or higher.
* @const
*/
Level.WARNING = new Level('WARNING', 900);
/**
* Log messages with a level of `800` or higher.
* @const
*/
Level.INFO = new Level('INFO', 800);
/**
* Log messages with a level of `700` or higher.
* @const
*/
Level.DEBUG = new Level('DEBUG', 700);
/**
* Log messages with a level of `500` or higher.
* @const
*/
Level.FINE = new Level('FINE', 500);
/**
* Log messages with a level of `400` or higher.
* @const
*/
Level.FINER = new Level('FINER', 400);
/**
* Log messages with a level of `300` or higher.
* @const
*/
Level.FINEST = new Level('FINEST', 300);
/**
* Indicates all log messages should be recorded.
* @const
*/
Level.ALL = new Level('ALL', 0);
const ALL_LEVELS = /** !Set<Level> */new Set([
Level.OFF,
Level.SEVERE,
Level.WARNING,
Level.INFO,
Level.DEBUG,
Level.FINE,
Level.FINER,
Level.FINEST,
Level.ALL
]);
const LEVELS_BY_NAME = /** !Map<string, !Level> */ new Map([
[Level.OFF.name, Level.OFF],
[Level.SEVERE.name, Level.SEVERE],
[Level.WARNING.name, Level.WARNING],
[Level.INFO.name, Level.INFO],
[Level.DEBUG.name, Level.DEBUG],
[Level.FINE.name, Level.FINE],
[Level.FINER.name, Level.FINER],
[Level.FINEST.name, Level.FINEST],
[Level.ALL.name, Level.ALL]
]);
/**
* Converts a level name or value to a {@link Level} value. If the name/value
* is not recognized, {@link Level.ALL} will be returned.
*
* @param {(number|string)} nameOrValue The log level name, or value, to
* convert.
* @return {!Level} The converted level.
*/
function getLevel(nameOrValue) {
if (typeof nameOrValue === 'string') {
return LEVELS_BY_NAME.get(nameOrValue) || Level.ALL;
}
if (typeof nameOrValue !== 'number') {
throw new TypeError('not a string or number');
}
for (let level of ALL_LEVELS) {
if (nameOrValue >= level.value) {
return level;
}
}
return Level.ALL;
}
/**
* Describes a single log entry.
*
* @final
*/
class Entry {
/**
* @param {(!Level|string|number)} level The entry level.
* @param {string} message The log message.
* @param {number=} opt_timestamp The time this entry was generated, in
* milliseconds since 0:00:00, January 1, 1970 UTC. If omitted, the
* current time will be used.
* @param {string=} opt_type The log type, if known.
*/
constructor(level, message, opt_timestamp, opt_type) {
this.level = level instanceof Level ? level : getLevel(level);
this.message = message;
this.timestamp =
typeof opt_timestamp === 'number' ? opt_timestamp : Date.now();
this.type = opt_type || '';
}
/**
* @return {{level: string, message: string, timestamp: number,
* type: string}} The JSON representation of this entry.
*/
toJSON() {
return {
'level': this.level.name,
'message': this.message,
'timestamp': this.timestamp,
'type': this.type
};
}
}
/** @typedef {(string|function(): string)} */
let Loggable;
/**
* An object used to log debugging messages. Loggers use a hierarchical,
* dot-separated naming scheme. For instance, "foo" is considered the parent of
* the "foo.bar" and an ancestor of "foo.bar.baz".
*
* Each logger may be assigned a {@linkplain #setLevel log level}, which
* controls which level of messages will be reported to the
* {@linkplain #addHandler handlers} attached to this instance. If a log level
* is not explicitly set on a logger, it will inherit its parent.
*
* This class should never be directly instantiated. Instead, users should
* obtain logger references using the {@linkplain ./logging.getLogger()
* getLogger()} function.
*
* @final
*/
class Logger {
/**
* @param {string} name the name of this logger.
* @param {Level=} opt_level the initial level for this logger.
*/
constructor(name, opt_level) {
/** @private {string} */
this.name_ = name;
/** @private {Level} */
this.level_ = opt_level || null;
/** @private {Logger} */
this.parent_ = null;
/** @private {Set<function(!Entry)>} */
this.handlers_ = null;
}
/** @return {string} the name of this logger. */
getName() {
return this.name_;
}
/**
* @param {Level} level the new level for this logger, or `null` if the logger
* should inherit its level from its parent logger.
*/
setLevel(level) {
this.level_ = level;
}
/** @return {Level} the log level for this logger. */
getLevel() {
return this.level_;
}
/**
* @return {!Level} the effective level for this logger.
*/
getEffectiveLevel() {
let logger = this;
let level;
do {
level = logger.level_;
logger = logger.parent_;
} while (logger && !level);
return level || Level.OFF;
}
/**
* @param {!Level} level the level to check.
* @return {boolean} whether messages recorded at the given level are loggable
* by this instance.
*/
isLoggable(level) {
return level.value !== Level.OFF.value
&& level.value >= this.getEffectiveLevel().value;
}
/**
* Adds a handler to this logger. The handler will be invoked for each message
* logged with this instance, or any of its descendants.
*
* @param {function(!Entry)} handler the handler to add.
*/
addHandler(handler) {
if (!this.handlers_) {
this.handlers_ = new Set;
}
this.handlers_.add(handler);
}
/**
* Removes a handler from this logger.
*
* @param {function(!Entry)} handler the handler to remove.
* @return {boolean} whether a handler was successfully removed.
*/
removeHandler(handler) {
if (!this.handlers_) {
return false;
}
return this.handlers_.delete(handler);
}
/**
* Logs a message at the given level. The message may be defined as a string
* or as a function that will return the message. If a function is provided,
* it will only be invoked if this logger's
* {@linkplain #getEffectiveLevel() effective log level} includes the given
* `level`.
*
* @param {!Level} level the level at which to log the message.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
log(level, loggable) {
if (!this.isLoggable(level)) {
return;
}
let message = '[' + this.name_ + '] '
+ (typeof loggable === 'function' ? loggable() : loggable);
let entry = new Entry(level, message, Date.now());
for (let logger = this; !!logger; logger = logger.parent_) {
if (logger.handlers_) {
for (let handler of logger.handlers_) {
handler(entry);
}
}
}
}
/**
* Logs a message at the {@link Level.SEVERE} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
severe(loggable) {
this.log(Level.SEVERE, loggable);
}
/**
* Logs a message at the {@link Level.WARNING} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
warning(loggable) {
this.log(Level.WARNING, loggable);
}
/**
* Logs a message at the {@link Level.INFO} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
info(loggable) {
this.log(Level.INFO, loggable);
}
/**
* Logs a message at the {@link Level.DEBUG} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
debug(loggable) {
this.log(Level.DEBUG, loggable);
}
/**
* Logs a message at the {@link Level.FINE} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
fine(loggable) {
this.log(Level.FINE, loggable);
}
/**
* Logs a message at the {@link Level.FINER} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
finer(loggable) {
this.log(Level.FINER, loggable);
}
/**
* Logs a message at the {@link Level.FINEST} log level.
* @param {(string|function(): string)} loggable the message to log, or a
* function that will return the message.
*/
finest(loggable) {
this.log(Level.FINEST, loggable);
}
}
/**
* Maintains a collection of loggers.
*
* @final
*/
class LogManager {
constructor() {
/** @private {!Map<string, !Logger>} */
this.loggers_ = new Map;
this.root_ = new Logger('', Level.OFF);
}
/**
* Retrieves a named logger, creating it in the process. This function will
* implicitly create the requested logger, and any of its parents, if they
* do not yet exist.
*
* @param {string} name the logger's name.
* @return {!Logger} the requested logger.
*/
getLogger(name) {
if (!name) {
return this.root_;
}
let parent = this.root_;
for (let i = name.indexOf('.'); i != -1; i = name.indexOf('.', i + 1)) {
let parentName = name.substr(0, i);
parent = this.createLogger_(parentName, parent);
}
return this.createLogger_(name, parent);
}
/**
* Creates a new logger.
*
* @param {string} name the logger's name.
* @param {!Logger} parent the logger's parent.
* @return {!Logger} the new logger.
* @private
*/
createLogger_(name, parent) {
if (this.loggers_.has(name)) {
return /** @type {!Logger} */(this.loggers_.get(name));
}
let logger = new Logger(name, null);
logger.parent_ = parent;
this.loggers_.set(name, logger);
return logger;
}
}
const logManager = new LogManager;
/**
* Retrieves a named logger, creating it in the process. This function will
* implicitly create the requested logger, and any of its parents, if they
* do not yet exist.
*
* The log level will be unspecified for newly created loggers. Use
* {@link Logger#setLevel(level)} to explicitly set a level.
*
* @param {string} name the logger's name.
* @return {!Logger} the requested logger.
*/
function getLogger(name) {
return logManager.getLogger(name);
}
/**
* Pads a number to ensure it has a minimum of two digits.
*
* @param {number} n the number to be padded.
* @return {string} the padded number.
*/
function pad(n) {
if (n >= 10) {
return '' + n;
} else {
return '0' + n;
}
}
/**
* Logs all messages to the Console API.
* @param {!Entry} entry the entry to log.
*/
function consoleHandler(entry) {
if (typeof console === 'undefined' || !console) {
return;
}
var timestamp = new Date(entry.timestamp);
var msg =
'[' + timestamp.getUTCFullYear() + '-' +
pad(timestamp.getUTCMonth() + 1) + '-' +
pad(timestamp.getUTCDate()) + 'T' +
pad(timestamp.getUTCHours()) + ':' +
pad(timestamp.getUTCMinutes()) + ':' +
pad(timestamp.getUTCSeconds()) + 'Z] ' +
'[' + entry.level.name + '] ' +
entry.message;
var level = entry.level.value;
if (level >= Level.SEVERE.value) {
console.error(msg);
} else if (level >= Level.WARNING.value) {
console.warn(msg);
} else {
console.log(msg);
}
}
/**
* Adds the console handler to the given logger. The console handler will log
* all messages using the JavaScript Console API.
*
* @param {Logger=} opt_logger The logger to add the handler to; defaults
* to the root logger.
*/
function addConsoleHandler(opt_logger) {
let logger = opt_logger || logManager.root_;
logger.addHandler(consoleHandler);
}
/**
* Removes the console log handler from the given logger.
*
* @param {Logger=} opt_logger The logger to remove the handler from; defaults
* to the root logger.
* @see exports.addConsoleHandler
*/
function removeConsoleHandler(opt_logger) {
let logger = opt_logger || logManager.root_;
logger.removeHandler(consoleHandler);
}
/**
* Installs the console log handler on the root logger.
*/
function installConsoleHandler() {
addConsoleHandler(logManager.root_);
}
/**
* Common log types.
* @enum {string}
*/
const Type = {
/** Logs originating from the browser. */
BROWSER: 'browser',
/** Logs from a WebDriver client. */
CLIENT: 'client',
/** Logs from a WebDriver implementation. */
DRIVER: 'driver',
/** Logs related to performance. */
PERFORMANCE: 'performance',
/** Logs from the remote server. */
SERVER: 'server'
};
/**
* Describes the log preferences for a WebDriver session.
*
* @final
*/
class Preferences {
constructor() {
/** @private {!Map<string, !Level>} */
this.prefs_ = new Map;
}
/**
* Sets the desired logging level for a particular log type.
* @param {(string|Type)} type The log type.
* @param {(!Level|string|number)} level The desired log level.
* @throws {TypeError} if `type` is not a `string`.
*/
setLevel(type, level) {
if (typeof type !== 'string') {
throw TypeError('specified log type is not a string: ' + typeof type);
}
this.prefs_.set(type, level instanceof Level ? level : getLevel(level));
}
/**
* Converts this instance to its JSON representation.
* @return {!Object<string, string>} The JSON representation of this set of
* preferences.
*/
toJSON() {
let json = {};
for (let key of this.prefs_.keys()) {
json[key] = this.prefs_.get(key).name;
}
return json;
}
}
// PUBLIC API
module.exports = {
Entry: Entry,
Level: Level,
LogManager: LogManager,
Logger: Logger,
Preferences: Preferences,
Type: Type,
addConsoleHandler: addConsoleHandler,
getLevel: getLevel,
getLogger: getLogger,
installConsoleHandler: installConsoleHandler,
removeConsoleHandler: removeConsoleHandler
};

3404
node_modules/selenium-webdriver/lib/promise.js generated vendored Normal file

File diff suppressed because it is too large Load diff

80
node_modules/selenium-webdriver/lib/session.js generated vendored Normal file
View file

@ -0,0 +1,80 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
const {Capabilities} = require('./capabilities');
/**
* Contains information about a single WebDriver session.
*/
class Session {
/**
* @param {string} id The session ID.
* @param {!(Object|Capabilities)} capabilities The session
* capabilities.
*/
constructor(id, capabilities) {
/** @private {string} */
this.id_ = id;
/** @private {!Capabilities} */
this.caps_ = capabilities instanceof Capabilities
? /** @type {!Capabilities} */(capabilities)
: new Capabilities(capabilities);
}
/**
* @return {string} This session's ID.
*/
getId() {
return this.id_;
}
/**
* @return {!Capabilities} This session's capabilities.
*/
getCapabilities() {
return this.caps_;
}
/**
* Retrieves the value of a specific capability.
* @param {string} key The capability to retrieve.
* @return {*} The capability value.
*/
getCapability(key) {
return this.caps_.get(key);
}
/**
* Returns the JSON representation of this object, which is just the string
* session ID.
* @return {string} The JSON representation of this Session.
*/
toJSON() {
return this.getId();
}
}
// PUBLIC API
module.exports = {Session: Session};

38
node_modules/selenium-webdriver/lib/symbols.js generated vendored Normal file
View file

@ -0,0 +1,38 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
/**
* @fileoverview Defines well-known symbols used within the selenium-webdriver
* library.
*/
module.exports = {
/**
* The serialize symbol specifies a method that returns an object's serialized
* representation. If an object's serialized form is not immediately
* available, the serialize method will return a promise that will be resolved
* with the serialized form.
*
* 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.
*/
serialize: Symbol('serialize')
};

151
node_modules/selenium-webdriver/lib/test/build.js generated vendored Normal file
View file

@ -0,0 +1,151 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict';
const spawn = require('child_process').spawn,
fs = require('fs'),
path = require('path');
const isDevMode = require('../devmode');
var projectRoot = path.normalize(path.join(__dirname, '../../../../..'));
function checkIsDevMode() {
if (!isDevMode) {
throw Error('Cannot execute build; not running in dev mode');
}
}
/**
* Targets that have been previously built.
* @type {!Object}
*/
var builtTargets = {};
/**
* @param {!Array.<string>} targets The targets to build.
* @throws {Error} If not running in dev mode.
* @constructor
*/
var Build = function(targets) {
checkIsDevMode();
this.targets_ = targets;
};
/** @private {boolean} */
Build.prototype.cacheResults_ = false;
/**
* Configures this build to only execute if it has not previously been
* run during the life of the current process.
* @return {!Build} A self reference.
*/
Build.prototype.onlyOnce = function() {
this.cacheResults_ = true;
return this;
};
/**
* Executes the build.
* @return {!Promise} A promise that will be resolved when
* the build has completed.
* @throws {Error} If no targets were specified.
*/
Build.prototype.go = function() {
var targets = this.targets_;
if (!targets.length) {
throw Error('No targets specified');
}
// Filter out cached results.
if (this.cacheResults_) {
targets = targets.filter(function(target) {
return !builtTargets.hasOwnProperty(target);
});
if (!targets.length) {
return Promise.resolve();
}
}
console.log('\nBuilding', targets.join(' '), '...');
var cmd, args = targets;
if (process.platform === 'win32') {
cmd = 'cmd.exe';
args.unshift('/c', path.join(projectRoot, 'go.bat'));
} else {
cmd = path.join(projectRoot, 'go');
}
return new Promise((resolve, reject) => {
spawn(cmd, args, {
cwd: projectRoot,
env: process.env,
stdio: ['ignore', process.stdout, process.stderr]
}).on('exit', function(code, signal) {
if (code === 0) {
targets.forEach(function(target) {
builtTargets[target] = 1;
});
return resolve();
}
var msg = 'Unable to build artifacts';
if (code) { // May be null.
msg += '; code=' + code;
}
if (signal) {
msg += '; signal=' + signal;
}
reject(Error(msg));
});
});
};
// PUBLIC API
/**
* Creates a build of the listed targets.
* @param {...string} var_args The targets to build.
* @return {!Build} The new build.
* @throws {Error} If not running in dev mode.
*/
exports.of = function(var_args) {
var targets = Array.prototype.slice.call(arguments, 0);
return new Build(targets);
};
/**
* @return {string} Absolute path of the project's root directory.
* @throws {Error} If not running in dev mode.
*/
exports.projectRoot = function() {
checkIsDevMode();
return projectRoot;
};

View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ClickTest_testClicksASurroundingStrongTag</title>
</head>
<body>
<div>
<a href="xhtmlTest.html"><strong>Click</strong></a>
</div>
</body>
</html>

View file

@ -0,0 +1,17 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Page.aspx.cs" Inherits="Page" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<a href="../xhtmlTest.html" target="_top">top</a>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>

View file

@ -0,0 +1,22 @@
using System;
using System.Threading;
public partial class Page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "text/html";
int lastIndex = Request.PathInfo.LastIndexOf("/");
string pageNumber = (lastIndex == -1 ? "Unknown" : Request.PathInfo.Substring(lastIndex + 1));
if (!string.IsNullOrEmpty(Request.QueryString["pageNumber"]))
{
pageNumber = Request.QueryString["pageNumber"];
}
Response.Output.Write("<html><head><title>Page" + pageNumber + "</title></head>");
Response.Output.Write("<body>Page number <span id=\"pageNumber\">");
Response.Output.Write(pageNumber);
//Response.Output.Write("<script>var s=''; for (var i in window) {s += i + ' -> ' + window[i] + '<p>';} document.write(s);</script>")'
Response.Output.Write("</span></body></html>");
}
}

View file

@ -0,0 +1,11 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Redirect.aspx.cs" Inherits="Redirect" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,9 @@
using System;
public partial class Redirect : Page
{
protected new void Page_Load(object sender, EventArgs e)
{
Response.Redirect("resultPage.html");
}
}

View file

@ -0,0 +1,759 @@
<StyleCopSettings Version="4.3">
<Analyzers>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustContainValidXml">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustMatchElementParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VoidReturnValueMustNotBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustNotBeEmpty">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustMeetCharacterPercentage">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustMeetMinimumCharacterLength">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationHeadersMustNotContainBlankLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludedDocumentationXPathDoesNotExist">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="CurlyBracketsForMultiLineStatementsMustNotShareLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustNotBeOnSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CurlyBracketsMustNotBeOmitted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningCurlyBracketsMustNotBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationHeadersMustNotBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainMultipleBlankLinesInARow">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingCurlyBracketsMustNotBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningCurlyBracketsMustNotBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ChainedStatementBlocksMustNotBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="WhileDoFooterMustNotBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingCurlyBracketMustBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationHeaderMustBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentMustBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeSeparatedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.MaintainabilityRules">
<Rules>
<Rule Name="AccessModifierMustBeDeclared">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldsMustBePrivate">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeAnalysisSuppressionMustHaveJustification">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DebugAssertMustProvideMessageText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DebugFailMustProvideMessageText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMayOnlyContainASingleClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileMayOnlyContainASingleNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotUseUnnecessaryParenthesis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ArithmeticExpressionsMustDeclarePrecedence">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConditionalExpressionsMustDeclarePrecedence">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="RemoveDelegateParenthesisWhenPossible">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="RemoveUnnecessaryCode">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="ElementMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementMustBeginWithLowerCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="InterfaceNamesMustBeginWithI">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstFieldNamesMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustNotUseHungarianNotation">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustBeginWithLowerCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="AccessibleFieldsMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VariableNamesMustNotBePrefixed">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustNotBeginWithUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustNotContainUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.OrderingRules">
<Rules>
<Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustAppearInTheCorrectOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeOrderedByAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstantsMustAppearBeforeFields">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StaticElementsMustAppearBeforeInstanceElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DeclarationKeywordsMustFollowOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ProtectedMustComeBeforeInternal">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertyAccessorsMustFollowOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EventAccessorsMustFollowOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UsingDirectivesMustBeOrderedAlphabeticallyByNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UsingAliasDirectivesMustBeOrderedAlphabeticallyByAliasName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="CommentsMustContainText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DoNotPrefixCallsWithBaseUnlessLocalImplementationExists">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PrefixLocalCallsWithThis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningParenthesisMustBeOnDeclarationLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingParenthesisMustBeOnLineOfLastParameter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingParenthesisMustBeOnLineOfOpeningParenthesis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CommaMustBeOnSameLineAsPreviousParameter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterListMustFollowDeclaration">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustFollowComma">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustNotSpanMultipleLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="QueryClauseMustFollowPreviousClause">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="QueryClausesMustBeOnSeparateLinesOrAllOnOneLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="QueryClauseMustBeginOnNewLineWhenPreviousClauseSpansMultipleLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="QueryClausesSpanningMultipleLinesMustBeginOnOwnLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DoNotPlaceRegionsWithinElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainEmptyStatements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainMultipleStatementsOnOneLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="BlockStatementsMustNotContainEmbeddedComments">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="BlockStatementsMustNotContainEmbeddedRegions">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UseStringEmptyForEmptyStrings">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UseBuiltInTypeAlias">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.SpacingRules">
<Rules>
<Rule Name="KeywordsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CommasMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SemicolonsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SymbolsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationLinesMustBeginWithSingleSpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustBeginWithSingleSpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PreprocessorKeywordsMustNotBePrecededBySpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OperatorKeywordMustBeFollowedBySpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningParenthesisMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingParenthesisMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningSquareBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingSquareBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningCurlyBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingCurlyBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningGenericBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingGenericBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="OpeningAttributeBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingAttributeBracketsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="NullableTypeSymbolsMustNotBePrecededBySpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="MemberAccessSymbolsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncrementDecrementSymbolsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="NegativeSignsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PositiveSignsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DereferenceAndAccessOfSymbolsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ColonsMustBeSpacedCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainMultipleWhitespaceInARow">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="CodeMustNotContainSpaceAfterNewKeywordInImplicitlyTypedArrayAllocation">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="TabsMustNotBeUsed">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

View file

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<!--
Note: As an alternative to hand editing this file you can use the
web admin tool to configure settings for your application. Use
the Website->Asp.Net Configuration option in Visual Studio.
A full list of settings and comments can be found in
machine.config.comments usually located in
\Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
<section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter"/>
</configSections>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<compilation debug="true" defaultLanguage="c#" targetFramework="4.0"/>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<httpModules>
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
</httpModules>
<!--urlMappings enabled="true">
<add url="~/redirect" mappedUrl="~/Redirect.aspx" />
</urlMappings-->
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/></system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule"/>
</modules>
</system.webServer>
<rewriter>
<rewrite url="~/redirect" to="~/Redirect.aspx"/>
<rewrite url="~/page/([0-9]+)$" to="~/Page.aspx?pageNumber=$1"/>
<rewrite url="~/page/([0-9]+)(\?)(.*)" to="~/Page.aspx?pageNumber=$1&amp;$3"/>
</rewriter>
</configuration>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
Title
</title>
</head>
<body>
<p>
<a href="/foo">Foo</a>
</p>
</body>
</html>

View file

@ -0,0 +1,81 @@
<!DOCTYPE html>
<html>
<body>
<form action="javascript:updateDom()">
<label for="typer">New label text:</label>
<input name="typer" type="text"/>
<br/>
<label for="color">Select label color:</label>
<input name="color" id="red" value="red" type="radio"/>Red
<input name="color" id="green" value="green" type="radio"/>Green
<br/>
<input name="submit" type="submit" value="Add Label"/>
</form>
<div id="update_butter" style="display:none"></div>
<script>
var butter = document.getElementById('update_butter');
var textProperty = butter['innerText'] ? 'innerText' : 'textContent';
var listeners = [];
function registerListener(fn) {
listeners.push(fn);
}
function updateDom() {
butter.style.display = 'block';
butter[textProperty] = 'Updating';
disableForm();
tick();
}
function disableForm() {
var inputs = document.getElementsByTagName('input');
for (var i = 0, input; input = inputs[i]; ++i) {
input.disabled = true;
}
}
function enableForm() {
var inputs = document.getElementsByTagName('input');
for (var i = 0, input; input = inputs[i]; ++i) {
input.disabled = false;
}
}
function tick() {
var length = butter[textProperty].substring('Updating'.length).length;
if (length != 10) {
butter[textProperty] += '.';
window.setTimeout(tick, 500);
} else {
enableForm();
var div = document.createElement('div');
var colors = document.forms[0].color;
for (var i = 0, color; color = colors[i]; ++i) {
if (color.checked) {
div.style.backgroundColor = color.value;
break;
}
}
div[textProperty] = document.forms[0].typer.value;
div.className = 'label';
document.forms[0].typer.value = '';
document.body.appendChild(div);
butter[textProperty] = 'Done!';
window.setTimeout(function() {
while (listeners.length) {
try {
listeners.shift()(div[textProperty]);
} catch (e) {
butter[textProperty] = "Exception seen: " + e;
}
}
}, 500);
}
}
</script>
</body>
</html>

View file

@ -0,0 +1,85 @@
<html>
<!-- Padding to account for small screens of mobile devices -->
<style>
p {margin-top:48px;}
</style>
<head>
<title>Testing Alerts</title>
<script type="text/javascript">
function setInnerText(id, value) {
document.getElementById(id).innerHTML = '<p>' + value + '</p>';
}
function displayPrompt() {
setInnerText('text', prompt('Enter something'));
}
function displayPromptWithDefault() {
setInnerText('text', prompt('Enter something', 'This is a default value'));
}
function displayTwoPrompts() {
setInnerText('text1', prompt('First'));
setInnerText('text2', prompt('Second'));
}
function slowAlert() {
window.setTimeout(function() {
alert('Slow');
}, 200);
}
</script>
</head>
<body>
<h1>Testing Alerts and Stuff</h1>
<p>This tests alerts: <a href="#" id="alert" onclick="alert('cheese');">click me</a></p>
<p>This tests alerts: <a href="#" id="empty-alert" onclick="alert('');">click me</a></p>
<p>Let's make the <a href="#" id="prompt" onclick="displayPrompt();">prompt happen</a></p>
<p>Let's make the <a href="#" id="prompt-with-default" onclick="displayPromptWithDefault();">prompt with default happen</a></p>
<p>Let's make TWO <a href="#" id="double-prompt" onclick="displayTwoPrompts();">prompts happen</a></p>
<p>A <a href="#" id="slow-alert" onclick="slowAlert();">SLOW</a> alert</p>
<p>This is a test of a confirm:
<a href="simpleTest.html" id="confirm" onclick="return confirm('Are you sure?');">test confirm</a></p>
<p>This is a test of showModalDialog: <a href="#" id="dialog" onclick="showModalDialog('javascriptPage.html')">test dialog</a></p>
<p>This is a test of an alert in an iframe:
<iframe src="iframeWithAlert.html" name="iframeWithAlert"></iframe>
</p>
<p>This is a test of an alert in a nested iframe:
<iframe src="iframeWithIframe.html" name="iframeWithIframe"></iframe>
</p>
<p>This is a test of an alert open from onload event handler: <a id="open-page-with-onload-alert" href="pageWithOnLoad.html">open new page</a></p>
<p>This is a test of an alert open from onload event handler: <a id="open-window-with-onload-alert" href="pageWithOnLoad.html" target="onload">open new window</a></p>
<p>This is a test of an alert open from onunload event handler: <a id="open-page-with-onunload-alert" href="pageWithOnUnload.html">open new page</a></p>
<p>This is a test of an alert open from onclose event handler: <a id="open-window-with-onclose-alert" href="pageWithOnUnload.html" target="onclose">open new window</a></p>
<p>This is a test of an alert open from onclose event handler: <a id="open-new-window" href="blank.html" target="newwindow">open new window</a></p>
<div id="text"></div>
<div id="text1"></div>
<div id="text2"></div>
<p><select id="select" onchange="alert('changed');">
<option id="novalue" value="">Nothing selected</option>
<option id="value1" value="1">One</option>
<option id="value2" value="2">Two</option>
<option id="value3" value="3">Three</option>
</select></p>
<p><input id="input" onchange="alert('change fired');" value="onchange"/></p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
node_modules/selenium-webdriver/lib/test/data/beach.jpg generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1 @@
<html><head><title>blank</title></head><body></body></html>

View file

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Testing Typing into body</title>
<script type="text/javascript">
function appendMessage(message) {
document.getElementById('result').innerHTML += message + " ";
}
function appendMessageFromBody(message) {
document.getElementById('body_result').innerHTML += message + " ";
}
</script>
</head>
<body onkeypress="appendMessageFromBody('keypress')">
<h1>Type Stuff</h1>
<div id="result">
&nbsp;
</div>
<div id="body_result">
&nbsp;
</div>
<!-- Textbox - to confuse some browsers. -->
<form action="resultPage.html" id="on-form">
<input id="intext"
onfocus="appendMessage('focus')"
onkeydown="appendMessage('keydown')"
onkeypress="appendMessage('keypress')"
onkeyup="appendMessage('keyup')"
onblur="appendMessage('blur')"
onchange="appendMessage('change')"
/>
</form>
</body>

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>Elements with boolean attributes</title>
</head>
<body>
<form method="get" action="resultPage.html" name="required">
<input type="text" id="working"/>
<input type="email" id="emailRequired" required/>
<input type="text" id="inputRequired" value="Example text" required=""/>
<textarea id="textAreaRequired" rows="5" cols="5" required="false">Example text</textarea>
<textarea id="emptyTextAreaRequired" rows="5" cols="5" required="required"></textarea>
</form>
<!-- Empty div to test GetAttribute -->
<div id="wallace" class="gromit"></div>
<!-- Div to test boolean attributes -->
<div id="unwrappable" nowrap>Unwrappable text</div>
</body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head>
<title>Depth one child page</title>
</head>
<body>
<p>I'm a page in a child directory</p>
</body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head>
<title>Depth two child page</title>
</head>
<body>
<p>I'm a page in a grandchild directory! How cute!</p>
</body>
</html>

View file

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Testing click events</title>
<script type="text/javascript">
function displayEvent(event) {
var keys = ['x', 'y', 'clientX', 'clientY', 'pageX', 'pageY', 'screenX', 'screenY', 'shiftKey', 'ctrlKey'];
var message = "<ul>";
for (var i = 0; i < keys.length; i++) {
message += "<li>" + keys[i] + ": <span id='" + keys[i] + "'>" + event[keys[i]] + "</span></li>";
}
message += "</ul>";
document.getElementById('result').innerHTML = message;
}
</script>
</head>
<body>
<div id="eventish" onclick="displayEvent(event);">
Click me to view my coordinates
</div>
<div id="result" style="width:300;height:60">
<p>&nbsp;</p>
</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<html>
<head>
<title>click frames</title>
</head>
<frameset rows="*" border="1">
<frame src="clicks.html" name="source" scrolling="NO" noresize>
<frame src="xhtmlTest.html" name="target">
</frameset>
</frameset>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>click-jacking</title>
<script>
var clickJacker;
function setOpacity(opacity) {
var matches = window.navigator.userAgent.match(/MSIE\s*(\d*)/);
if (matches && matches.length > 1 && parseInt(matches[1]) <= 8) {
clickJacker.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
} else {
clickJacker.style.opacity = opacity;
}
}
function init() {
clickJacker = document.getElementById('clickJacker');
setOpacity(0);
}
</script>
</head>
<body onload="init()">
<div>
<div id="clickJacker"
onclick="setOpacity(1);"
style="position:absolute;float:left;
width:200px;height:100px; padding:10px;
background-color:darkred;
border:1px solid darkred;">Click jacked!</div>
<div style="width:200px; height:100px;
border:1px solid black; padding:10px">Click Me</div>
<script>
clickJacker = document.getElementById('clickJacker');
</script>
</div>
</body>
</html>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<body>
<table>
<tr>
<td>
<div style="width:752px;"></div>
</td>
<td>
<div style="width:350px; text-align: center;">
<form onsubmit="return false;" method="get">
<input id="button" value="Click me" type="submit">
</form>
</div>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<div style="height: 100px; overflow: auto;">
<table>
<tbody>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td><a href="#clicked" id="link">click me</a></td></tr>
</tbody>
</table>
</div>
</body></html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>RTL test</title>
<style type="text/css">
.test { font-size: 150%; }
table td { border: 1px solid #CCC; }
img { margin: 10px; }
</style>
</head>
<body>
<div dir="rtl">
<div class="test">مفتاح<a href="clicks.html" id="ar_link"> معايير</a> الويب</div>
<div class="test">פעילות<a id="hb_link" href="clicks.html"> הבינאום </a></div>
</div>
</body></html>

View file

@ -0,0 +1,18 @@
<html>
<head>
<title>Click Source</title>
</head>
<body>
<a href="simpleTest.html" target="target" id="otherframe">I go to a target</a>
</body>
</html>
<html>
<head>
<title>Click Source</title>
</head>
<body>
<a href="simpleTest.html" target="target" id="otherframe">I go to a target</a>
</body>
</html>

View file

@ -0,0 +1,6 @@
<html>
<head>
<title>click iframe</title>
</head>
<body><a id="link" href="submitted_page.html" target="_top">Click me</a></body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head>
<title>click in iframe</title>
</head>
<body>
<iframe id="ifr" src="click_iframe.html" style="margin: 200px; width: 100px; height: 50px;" />
</body>
</html>

View file

@ -0,0 +1,62 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>An element that disappears on click</title>
<style>
#under {
position: absolute;
top: 20;
left: 20;
width: 100px;
height: 100px;
background-color: white;
}
#over {
position: absolute;
top: 20;
left: 20;
width: 100px;
height: 100px;
background-color: red;
opacity: 0.5;
}
#log {
position: absolute;
top: 120px;
}
</style>
</head>
<body id="body">
<div id="under"><p id="contents">Hello</p></div>
<div id="over"></div>
<div id="log">
<p>Log:<p>
</div>
<script>
var byId = document.getElementById.bind(document);
var log = byId("log");
function handler(ev) {
log.innerHTML += "<p></p>";
log.lastElementChild.textContent = ev.type + " in " + ev.target.id + " (handled by " + ev.currentTarget.id + ")\n";
}
var under = byId("under");
var over = byId("over");
var body = document.body;
var types = ["click", "mousedown", "mouseup"];
for (var i = 0, type; (type = types[i]); ++i) {
under.addEventListener(type, handler);
over.addEventListener(type, handler);
body.addEventListener(type, handler);
}
over.addEventListener("mousedown", function () {
over.style.display = "none";
})
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Google Image Map</title>
</head>
<body>
<h1>Google Image Map</h1>
<img id="google_logo" src="google_map.png" usemap="#google_map" border="0" width="364" height="126"/>
<map id="google_map" name="google_map">
<area id="rectG" shape="rect" coords="0,0,90,100" href="mapped_page1.html" alt="area 1"/>
<area id="circleO" shape="circle" coords="120,60,30" href="mapped_page2.html" alt="area 2"/>
<area id="polyLE" shape="poly" coords="280,0,310,0,360,30,360,90,280,90" href="mapped_page3.html" alt="area 3"/>
</map>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Submit Buttons</title>
</head>
<body>
<form id="form1" action="submitted_page.html">
<label for="name">Enter your name: </label><input type="text" name="name" id="name"/>
<button id="internal_explicit_submit" type="submit">Explicit Submit</button>
<button id="internal_implicit_submit">Implicit Submit</button>
<button type="submit"><span id="internal_span_submit">Spanned Submit</span></button>
</form>
<button id="external_explicit_submit" type="submit" form="form1">Explicit Submit</button>
<button id="external_implicit_submit" form="form1">Implicit Submit</button>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Sample page for issue 5237</title>
</head>
<body>
<iframe id="search" src="issue5237_frame.html"></iframe>
</body>
</html>

View file

@ -0,0 +1 @@
<a id="submit" href="#" onclick="window.top.location = 'issue5237_target.html'; return false;">Continue</a>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Target page for issue 5237</title>
</head>
<body>
<h1>Test passed</h1>
</map>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Link that continues on next line</title>
</head>
<body>
<div style="width:300px">
<div style="float:left;width:200px;background:red">placeholder</div><a id="link" href="submitted_page.html">Link that continues on next line</a>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Target Page 1</title>
</head>
<body>
<div>Target Page 1</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Target Page 2</title>
</head>
<body>
<div>Target Page 2</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Target Page 3</title>
</head>
<body>
<div>Target Page 3</div>
</body>
</html>

View file

@ -0,0 +1,70 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>An element that disappears on click</title>
<style>
#under {
position: absolute;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
background-color: white;
}
#partially_under {
position: absolute;
top: 20px;
left: 10px;
width: 100px;
height: 100px;
background-color: blue;
opacity: 0.5;
}
#over {
position: absolute;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
background-color: red;
opacity: 0.5;
}
#log {
position: absolute;
top: 120px;
}
</style>
</head>
<body id="body">
<div id="under"><p id="contents">Hello</p></div>
<div id="partially_under"><p id="other_contents">Hello</p></div>
<div id="over"></div>
<div id="log">
<p>Log:<p>
</div>
<script>
var byId = document.getElementById.bind(document);
var log = byId("log");
function handler(ev) {
log.innerHTML += "<p></p>";
log.lastElementChild.textContent = ev.type + " in " + ev.target.id + " (handled by " + ev.currentTarget.id + ")\n";
}
var under = byId("under");
var over = byId("over");
var body = document.body;
var types = ["click", "mousedown", "mouseup"];
for (var i = 0, type; (type = types[i]); ++i) {
under.addEventListener(type, handler);
over.addEventListener(type, handler);
body.addEventListener(type, handler);
}
</script>
</body>
</html>

View file

@ -0,0 +1,124 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>An element that disappears on click</title>
<style>
#under_under {
position: absolute;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
background-color: white;
}
#under {
position: absolute;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
background-color: blue;
opacity: 0.1;
}
#over1 {
position: absolute;
top: 10px;
left: 10px;
width: 50px;
height: 50px;
background-color: red;
opacity: 0.2;
}
#over2 {
position: absolute;
top: 80px;
left: 10px;
width: 50px;
height: 50px;
background-color: red;
opacity: 0.2;
}
#over3 {
position: absolute;
top: 10px;
left: 80px;
width: 50px;
height: 50px;
background-color: red;
opacity: 0.2;
}
#over4 {
position: absolute;
top: 80px;
left: 80px;
width: 50px;
height: 50px;
background-color: red;
opacity: 0.2;
}
#over5 {
position: absolute;
top: 45px;
left: 45px;
width: 50px;
height: 50px;
background-color: red;
opacity: 0.2;
}
#log {
position: absolute;
top: 120px;
}
</style>
</head>
<body id="body">
<div id="under_under"><p id="contents">Hello</p></div>
<div id="under"><p id="other_contents">Hello</p></div>
<div id="over1"></div>
<div id="over2"></div>
<div id="over3"></div>
<div id="over4"></div>
<div id="over5"></div>
<div id="log">
<p>Log:<p>
</div>
<script>
var byId = document.getElementById.bind(document);
var log = byId("log");
function handler(ev) {
log.innerHTML += "<p></p>";
log.lastElementChild.textContent = ev.type + " in " + ev.target.id + " (handled by " + ev.currentTarget.id + ")\n";
}
var under_under = byId("under_under");
var under = byId("under");
var over1 = byId("over1");
var over2 = byId("over2");
var over3 = byId("over3");
var over4 = byId("over4");
var over5 = byId("over5");
var body = document.body;
var types = ["click", "mousedown", "mouseup"];
for (var i = 0, type; (type = types[i]); ++i) {
under_under.addEventListener(type, handler);
under.addEventListener(type, handler);
over1.addEventListener(type, handler);
over2.addEventListener(type, handler);
over3.addEventListener(type, handler);
over4.addEventListener(type, handler);
over5.addEventListener(type, handler);
body.addEventListener(type, handler);
}
</script>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Link that continues on next line</title>
</head>
<body>
<div style="width:300px">
<div style="float:left;width:200px;background:red">placeholder</div><span id="span" onclick="document.location='submitted_page.html'">Span that continues on next line</span>
</div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Submitted Successfully!</title>
</head>
<body>
<h1>Submitted Successfully!</h1>
</body>
</html>

View file

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>A wrapped element with overlapped first part</title>
</head>
<body id="body">
<div style="width:300px">
<div style="float:left;width:200px;background:green;">placeholder</div>
<div style="float:left; position:absolute;width:100px;margin-left:200px;background:red;opacity:0.5;">Over</div>
<a id="link" href="submitted_page.html">Link that continues on next line</a>
</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<body>
<a id="click" href="clicks.html" target="_parent">
<div style="width: 10001px; height: 10001px; background-color: green;">
&nbsp; &nbsp; &nbsp;
</div>
</a>
</body>
</html>

View file

@ -0,0 +1,11 @@
<html>
<head>
<title>This page has iframes</title>
</head>
<body>
<h1 id="iframe_page_heading">This is the heading</h1>
<iframe src="click_too_big.html" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true"
frameborder="0" height="10001" scrolling="no" width="10001" id="iframe1" name="iframe1-name" />
</body>
</html>

View file

@ -0,0 +1,35 @@
<html>
<head>
<title>clicks</title>
</head>
<body>
<h1>Testing Clicks</h1>
<iframe id="source" src="click_source.html">
</iframe>
<iframe id="target" name="target">
</iframe>
<br>
<a href="xhtmlTest.html" id="normal">I'm a normal link</a>
<br/>
<a href="#" id="anchor">I go to an anchor</a>
<br>
<a href="javascript:window.open('xhtmlTest.html', '_blank')" id="new-window">I open a window with javascript</a>
<br/>
<a href="xhtmlTest.html" id="twoClientRects"><span></span><span>Click me</span></a>
<br/>
<a href="xhtmlTest.html" id="link-with-enclosed-image"><img id="enclosed-image" src="./icon.gif"/></a>
<br/>
<a href="xhtmlTest.html" id="link-with-enclosed-span"><span id="enclosed-span" style="color: rgb(0, 255, 0)">I'm a green link</span></a>
<p style="background: none repeat scroll 0% 0% rgb(0, 255, 0); width: 5em;"><a id="overflowLink" href="xhtmlTest.html">looooooooooong short looooooooooong</a>
</p>
<div id="bubblesTo" onclick="window.bubbledClick = true;">
<a id="bubblesFrom">I bubble</a>
</div>
<a href="xhtmlTest.html">333333</a>
<p><a href="xhtmlTest.html" id="embeddedBlock"><span style="display: block;">I have a span</span><div>And a div</div><span>And another span</span></a></p>
</body>
</html>

View file

@ -0,0 +1,8 @@
<html>
<head>
<title>closeable window</title>
</head>
<body>
This window can be closed by clicking on <a id="close" onclick="window.setTimeout(function() { window.close();}, 0);" href="#">this</a>.
</body>
</html>

View file

@ -0,0 +1,156 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
/* default css */
table {
font-size: 1em;
line-height: inherit;
}
div, address, ol, ul, li, option, select {
margin-top: 0px;
margin-bottom: 0px;
}
p {
margin: 0px;
}
body {
margin: 0px;
padding-left: 50px;
padding-right: 50px;
padding-top: 40px;
}
h6 { font-size: 10pt }
h5 { font-size: 11pt }
h4 { font-size: 12pt }
h3 { font-size: 13pt }
h2 { font-size: 14pt }
h1 { font-size: 16pt }
blockquote {padding: 10px; border: 1px #DDD dashed }
a img {border: 0}
div.google_header, div.google_footer {
position: relative;
margin-top: 1em;
margin-bottom: 1em;
}
/* end default css */
/* default print css */
@media print {
body {
padding: 0;
margin: 0;
}
div.google_header, div.google_footer {
display: block;
min-height: 0;
border: none;
}
div.google_header {
flow: static(header);
}
/* used to insert page numbers */
div.google_header::before, div.google_footer::before {
position: absolute;
top: 0;
}
div.google_footer {
flow: static(footer);
}
/* always consider this element at the start of the doc */
div#google_footer {
flow: static(footer, start);
}
span.google_pagenumber {
content: counter(page);
}
span.google_pagecount {
content: counter(pages);
}
}
@page {
@top {
content: flow(header);
}
@bottom {
content: flow(footer);
}
}
/* end default print css */
/* custom css */
/* end custom css */
/* ui edited css */
body {
font-family: Verdana;
font-size: 10.0pt;
line-height: normal;
background-color: #ffffff;
}
/* end ui edited css */
</style>
</head>
<body revision="cczv65wb_54f62cc9f2:3">
<div id="result">
</div>
<h1>展望2008世界大势风起云涌 激荡人心</h1><br>
<br>
8月8日晚北京2008年奥运会倒计时一周年庆祝活动在天安门广场举行。图为庆祝活动中的文艺演出。 新华社记者刘卫兵摄
2008年世界风起云涌,激荡人心。但要作出一个预测,首先要对今天所处的世界有一个基本共识。<br>
<br>
<a href=simpleTest.html id=b7v9 title=中国之声>中国之声</a><br>
<br>
<br>
<form action="simpleTest.html">
<input name="i18n" onchange="document.getElementById('result').innerHTML = '<p>' + this.value + '</p>';" />
</form>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Color Page</title>
</head>
<body>
<div id="namedColor" style="background-color: green;">namedColor</div>
<div id="rgb" style="background-color: rgb(0,128,0);">rgb</div>
<div id="rgbpct" style="background-color: rgb(0%,50%,0%);">rgbpct</div>
<div id="hex" style="background-color: #008000;">hex</div>
<div id="hexShort" style="background-color: #eee;">hex</div>
<div id="hsl" style="background-color: hsl(120,100%,25%);">hsl</div>
<div id="rgba" style="background-color: rgba(0,128,0, 0.5);">rgba</div>
<div id="rgbapct" style="background-color: rgba(0%,50%,0%, 0.5);">rgba</div>
<div id="hsla" style="background-color: hsla(120,100%,25%,0.5);">hsla</div>
</body>
</html>

View file

@ -0,0 +1,30 @@
<html>
<head>
<title>Testing cookies</title>
<script type="text/javascript">
function setCookie(domain, name) {
document.cookie = name + "=ok;path=/;domain=" + domain;
}
function showCookie() {
document.getElementById("result").innerHTML = "<p>" + document.cookie + "</p>";
}
</script>
</head>
<body onload="showCookie();">
<h2>Cookie Mashing</h2>
.com <a href="#" onclick="setCookie('.com', 'the.com_one'); showCookie(); return false;">Click</a></br />
. <a href="#" onclick="setCookie('.', 'the.one'); showCookie(); return false;">Click</a></br />
google.com <a href="#" onclick="setCookie('google.com', 'google'); showCookie(); return false;">Click</a></br />
.google.com <a href="#" onclick="setCookie('.google.com', '.google'); showCookie(); return false;">Click</a></br />
127.0.0.1 <a href="#" onclick="setCookie('127.0.0.1', 'localhost'); showCookie(); return false;">Click</a></br />
localhost:3001 <a href="#" onclick="setCookie('mency.ad.corp.google.com:62210', 'with_port'); showCookie(); return false;">Click</a></br />
.google:3001 <a href="#" onclick="setCookie('.google.com:62210', 'with_domain_and_port'); showCookie(); return false;">Click</a></br />
172.16.12.225 <a href="#" onclick="setCookie('172.16.12.225', 'raw_IP'); showCookie(); return false;">Click</a></br />
172.16.12.225:port <a href="#" onclick="setCookie('172.16.12.225:62210', 'raw_IP_and_port'); showCookie(); return false;">Click</a></br />
<a href="#" onclick="document.cookie = 'foo=bar;path=/common/galaxy';">Set on a different path</a>
<div id="result"></div>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome Page</title>
</head>
<body style="margin: 10px; padding: 0px;">
<iframe name="ifr" src="simple_page.html" width="400" height="300" style="border: 5px solid;"></iframe>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome Page</title>
</head>
<body style="margin: 10px; padding: 0px;">
<iframe name="ifr" src="element_in_frame.html" width="500" height="400" style="border: 5px solid;"></iframe>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Element Out Of View</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div style="height: 5000px;">Placeholder</div>
<div id="box" style="width: 100px; height: 100px; background-color: red;">Red box</div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Empty Element</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div id="box"></div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Fixed Element</title>
</head>
<body>
<div id="fixed" style="position:fixed; top:0px; left:100px; background-color:red">fixed red box</div>
<div id="placeholder" style="height: 5000px; background-color:green">Placeholder</div>
<div id="bottom">Element at the bottom</div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Hidden Element</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div id="box" style="width: 100px; height: 100px; background-color: red; visibility: hidden;">Hidden box</div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Invisible Element</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div id="box" style="width: 100px; height: 100px; background-color: red; display: none;">Invisible box</div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Page With Transparent Element</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div id="box" style="width: 100px; height: 100px; background-color: red; opacity: 0;">Hidden box</div>
<div>Tex after box</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Simple Page</title>
</head>
<body style="margin: 10px; padding: 0px;">
<div id="box" style="width: 100px; height: 100px; background-color: red;">Red box</div>
<div>Tex after box</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Some files were not shown because too many files have changed in this diff Show more