Deployed the page to Github Pages.
2
node_modules/selenium-webdriver/.npmignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
|
851
node_modules/selenium-webdriver/CHANGES.md
generated
vendored
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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;
|
42
node_modules/selenium-webdriver/example/chrome_android.js
generated
vendored
Normal 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));
|
42
node_modules/selenium-webdriver/example/chrome_mobile_emulation.js
generated
vendored
Normal 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));
|
50
node_modules/selenium-webdriver/example/google_search.js
generated
vendored
Normal 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());
|
47
node_modules/selenium-webdriver/example/google_search_generator.js
generated
vendored
Normal 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));
|
60
node_modules/selenium-webdriver/example/google_search_test.js
generated
vendored
Normal 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
|
@ -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());
|
51
node_modules/selenium-webdriver/example/parallel_flows.js
generated
vendored
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
80
node_modules/selenium-webdriver/lib/session.js
generated
vendored
Normal 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
|
@ -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
|
@ -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;
|
||||
};
|
11
node_modules/selenium-webdriver/lib/test/data/ClickTest_testClicksASurroundingStrongTag.html
generated
vendored
Normal 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>
|
17
node_modules/selenium-webdriver/lib/test/data/Page.aspx
generated
vendored
Normal 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>
|
22
node_modules/selenium-webdriver/lib/test/data/Page.aspx.cs
generated
vendored
Normal 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>");
|
||||
}
|
||||
}
|
11
node_modules/selenium-webdriver/lib/test/data/Redirect.aspx
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/Redirect.aspx.cs
generated
vendored
Normal 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");
|
||||
}
|
||||
}
|
759
node_modules/selenium-webdriver/lib/test/data/Settings.StyleCop
generated
vendored
Normal 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>
|
59
node_modules/selenium-webdriver/lib/test/data/Web.Config
generated
vendored
Normal 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&$3"/>
|
||||
</rewriter>
|
||||
</configuration>
|
14
node_modules/selenium-webdriver/lib/test/data/actualXhtmlPage.xhtml
generated
vendored
Normal 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>
|
81
node_modules/selenium-webdriver/lib/test/data/ajaxy_page.html
generated
vendored
Normal 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>
|
85
node_modules/selenium-webdriver/lib/test/data/alerts.html
generated
vendored
Normal 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>
|
BIN
node_modules/selenium-webdriver/lib/test/data/banner.gif
generated
vendored
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
node_modules/selenium-webdriver/lib/test/data/beach.jpg
generated
vendored
Normal file
After Width: | Height: | Size: 14 KiB |
1
node_modules/selenium-webdriver/lib/test/data/blank.html
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<html><head><title>blank</title></head><body></body></html>
|
41
node_modules/selenium-webdriver/lib/test/data/bodyTypingTest.html
generated
vendored
Normal 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">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="body_result">
|
||||
|
||||
</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>
|
||||
|
19
node_modules/selenium-webdriver/lib/test/data/booleanAttributes.html
generated
vendored
Normal 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>
|
8
node_modules/selenium-webdriver/lib/test/data/child/childPage.html
generated
vendored
Normal 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>
|
8
node_modules/selenium-webdriver/lib/test/data/child/grandchild/grandchildPage.html
generated
vendored
Normal 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>
|
26
node_modules/selenium-webdriver/lib/test/data/clickEventPage.html
generated
vendored
Normal 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> </p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
10
node_modules/selenium-webdriver/lib/test/data/click_frames.html
generated
vendored
Normal 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>
|
38
node_modules/selenium-webdriver/lib/test/data/click_jacker.html
generated
vendored
Normal 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>
|
23
node_modules/selenium-webdriver/lib/test/data/click_out_of_bounds.html
generated
vendored
Normal 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>
|
85
node_modules/selenium-webdriver/lib/test/data/click_out_of_bounds_overflow.html
generated
vendored
Normal 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>
|
19
node_modules/selenium-webdriver/lib/test/data/click_rtl.html
generated
vendored
Normal 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>
|
18
node_modules/selenium-webdriver/lib/test/data/click_source.html
generated
vendored
Normal 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>
|
||||
|
6
node_modules/selenium-webdriver/lib/test/data/click_tests/click_iframe.html
generated
vendored
Normal 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>
|
8
node_modules/selenium-webdriver/lib/test/data/click_tests/click_in_iframe.html
generated
vendored
Normal 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>
|
62
node_modules/selenium-webdriver/lib/test/data/click_tests/disappearing_element.html
generated
vendored
Normal 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>
|
15
node_modules/selenium-webdriver/lib/test/data/click_tests/google_map.html
generated
vendored
Normal 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>
|
BIN
node_modules/selenium-webdriver/lib/test/data/click_tests/google_map.png
generated
vendored
Normal file
After Width: | Height: | Size: 26 KiB |
16
node_modules/selenium-webdriver/lib/test/data/click_tests/html5_submit_buttons.html
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/click_tests/issue5237.html
generated
vendored
Normal 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>
|
1
node_modules/selenium-webdriver/lib/test/data/click_tests/issue5237_frame.html
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<a id="submit" href="#" onclick="window.top.location = 'issue5237_target.html'; return false;">Continue</a>
|
10
node_modules/selenium-webdriver/lib/test/data/click_tests/issue5237_target.html
generated
vendored
Normal 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>
|
11
node_modules/selenium-webdriver/lib/test/data/click_tests/link_that_wraps.html
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/click_tests/mapped_page1.html
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Target Page 1</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Target Page 1</div>
|
||||
</body>
|
||||
</html>
|
9
node_modules/selenium-webdriver/lib/test/data/click_tests/mapped_page2.html
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Target Page 2</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Target Page 2</div>
|
||||
</body>
|
||||
</html>
|
9
node_modules/selenium-webdriver/lib/test/data/click_tests/mapped_page3.html
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Target Page 3</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Target Page 3</div>
|
||||
</body>
|
||||
</html>
|
70
node_modules/selenium-webdriver/lib/test/data/click_tests/overlapping_elements.html
generated
vendored
Normal 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>
|
124
node_modules/selenium-webdriver/lib/test/data/click_tests/partially_overlapping_elements.html
generated
vendored
Normal 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>
|
11
node_modules/selenium-webdriver/lib/test/data/click_tests/span_that_wraps.html
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/click_tests/submitted_page.html
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Submitted Successfully!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Submitted Successfully!</h1>
|
||||
</body>
|
||||
</html>
|
13
node_modules/selenium-webdriver/lib/test/data/click_tests/wrapped_overlapping_elements.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/click_too_big.html
generated
vendored
Normal 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;">
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
11
node_modules/selenium-webdriver/lib/test/data/click_too_big_in_frame.html
generated
vendored
Normal 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>
|
35
node_modules/selenium-webdriver/lib/test/data/clicks.html
generated
vendored
Normal 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>
|
8
node_modules/selenium-webdriver/lib/test/data/closeable_window.html
generated
vendored
Normal 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>
|
156
node_modules/selenium-webdriver/lib/test/data/cn-test.html
generated
vendored
Normal 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>
|
20
node_modules/selenium-webdriver/lib/test/data/colorPage.html
generated
vendored
Normal 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>
|
||||
|
||||
|
||||
|
30
node_modules/selenium-webdriver/lib/test/data/cookies.html
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/element_in_frame.html
generated
vendored
Normal 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>
|
9
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/element_in_nested_frame.html
generated
vendored
Normal 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>
|
11
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_element_out_of_view.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_empty_element.html
generated
vendored
Normal 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>
|
12
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_fixed_element.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_hidden_element.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_invisible_element.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/page_with_transparent_element.html
generated
vendored
Normal 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>
|
10
node_modules/selenium-webdriver/lib/test/data/coordinates_tests/simple_page.html
generated
vendored
Normal 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>
|
BIN
node_modules/selenium-webdriver/lib/test/data/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png
generated
vendored
Normal file
After Width: | Height: | Size: 260 B |
BIN
node_modules/selenium-webdriver/lib/test/data/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png
generated
vendored
Normal file
After Width: | Height: | Size: 251 B |
BIN
node_modules/selenium-webdriver/lib/test/data/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png
generated
vendored
Normal file
After Width: | Height: | Size: 178 B |
BIN
node_modules/selenium-webdriver/lib/test/data/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png
generated
vendored
Normal file
After Width: | Height: | Size: 104 B |
BIN
node_modules/selenium-webdriver/lib/test/data/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png
generated
vendored
Normal file
After Width: | Height: | Size: 125 B |