From fdb9c2713474dd86bb35b7448dbd6b3d4a423f43 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Mon, 20 May 2024 09:50:09 +0200 Subject: [PATCH] [js] Running format script --- javascript/node/selenium-webdriver/chrome.js | 169 +- .../node/selenium-webdriver/chromium.js | 1492 ++++++++--------- javascript/node/selenium-webdriver/edge.js | 141 +- javascript/node/selenium-webdriver/firefox.js | 1093 ++++++------ javascript/node/selenium-webdriver/ie.js | 826 +++++---- .../node/selenium-webdriver/jsdoc_conf.json | 8 +- javascript/node/selenium-webdriver/safari.js | 154 +- 7 files changed, 1911 insertions(+), 1972 deletions(-) diff --git a/javascript/node/selenium-webdriver/chrome.js b/javascript/node/selenium-webdriver/chrome.js index 484da7dd7edb5..9d644ba9666f6 100644 --- a/javascript/node/selenium-webdriver/chrome.js +++ b/javascript/node/selenium-webdriver/chrome.js @@ -122,11 +122,11 @@ * @module selenium-webdriver/chrome */ -"use strict"; +'use strict' -const { Browser } = require("./lib/capabilities"); -const chromium = require("./chromium"); -const CHROME_CAPABILITY_KEY = "goog:chromeOptions"; +const { Browser } = require('./lib/capabilities') +const chromium = require('./chromium') +const CHROME_CAPABILITY_KEY = 'goog:chromeOptions' /** @type {remote.DriverService} */ @@ -136,105 +136,104 @@ const CHROME_CAPABILITY_KEY = "goog:chromeOptions"; * server in a child process. */ class ServiceBuilder extends chromium.ServiceBuilder { - /** - * @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. If the chromedriver is not available in path, selenium-manager will - * download the chromedriver - * @throws {Error} If provided executable does not exist, or the chromedriver - * cannot be found on the PATH. - */ - constructor (opt_exe) { - super(opt_exe); - } + /** + * @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. If the chromedriver is not available in path, selenium-manager will + * download the chromedriver + * @throws {Error} If provided executable does not exist, or the chromedriver + * cannot be found on the PATH. + */ + constructor(opt_exe) { + super(opt_exe) + } } /** * Class for managing ChromeDriver specific options. */ class Options extends chromium.Options { - /** - * 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) { - return this.setBinaryPath(path); - } + /** + * 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) { + return this.setBinaryPath(path) + } - /** - * 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"); - } + /** + * 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 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) { - return this.setBrowserLogFile(path); - } + /** + * 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) { + return this.setBrowserLogFile(path) + } - /** - * 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) { - return this.setBrowserMinidumpPath(path); - } + /** + * 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) { + return this.setBrowserMinidumpPath(path) + } } /** * Creates a new WebDriver client for Chrome. */ class Driver extends chromium.Driver { - /** - * 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. - * @return {!Driver} A new driver instance. - */ - static createSession (opt_config, opt_serviceExecutor) { - let caps = opt_config || new Options(); - return /** @type {!Driver} */ (super.createSession(caps, - opt_serviceExecutor, "goog", CHROME_CAPABILITY_KEY)); - } + /** + * 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. + * @return {!Driver} A new driver instance. + */ + static createSession(opt_config, opt_serviceExecutor) { + let caps = opt_config || new Options() + return /** @type {!Driver} */ (super.createSession(caps, opt_serviceExecutor, 'goog', CHROME_CAPABILITY_KEY)) + } - /** - * returns new instance chrome driver service - * @returns {remote.DriverService} - */ - static getDefaultService () { - return new ServiceBuilder().build(); - } + /** + * returns new instance chrome driver service + * @returns {remote.DriverService} + */ + static getDefaultService() { + return new ServiceBuilder().build() + } } -Options.prototype.CAPABILITY_KEY = CHROME_CAPABILITY_KEY; -Options.prototype.BROWSER_NAME_VALUE = Browser.CHROME; +Options.prototype.CAPABILITY_KEY = CHROME_CAPABILITY_KEY +Options.prototype.BROWSER_NAME_VALUE = Browser.CHROME // PUBLIC API module.exports = { - Driver, - Options, - ServiceBuilder -}; + Driver, + Options, + ServiceBuilder, +} diff --git a/javascript/node/selenium-webdriver/chromium.js b/javascript/node/selenium-webdriver/chromium.js index ee0d7fdc3afd7..3a3f335e06e70 100644 --- a/javascript/node/selenium-webdriver/chromium.js +++ b/javascript/node/selenium-webdriver/chromium.js @@ -70,37 +70,37 @@ * @module selenium-webdriver/chromium */ -"use strict"; - -const http = require("./http"); -const io = require("./io"); -const { Capabilities, Capability } = require("./lib/capabilities"); -const command = require("./lib/command"); -const error = require("./lib/error"); -const Symbols = require("./lib/symbols"); -const webdriver = require("./lib/webdriver"); -const remote = require("./remote"); -const { getBinaryPaths } = require("./common/driverFinder"); +'use strict' + +const http = require('./http') +const io = require('./io') +const { Capabilities, Capability } = require('./lib/capabilities') +const command = require('./lib/command') +const error = require('./lib/error') +const Symbols = require('./lib/symbols') +const webdriver = require('./lib/webdriver') +const remote = require('./remote') +const { getBinaryPaths } = require('./common/driverFinder') /** * Custom command names supported by Chromium WebDriver. * @enum {string} */ const Command = { - LAUNCH_APP: "launchApp", - GET_NETWORK_CONDITIONS: "getNetworkConditions", - SET_NETWORK_CONDITIONS: "setNetworkConditions", - DELETE_NETWORK_CONDITIONS: "deleteNetworkConditions", - SEND_DEVTOOLS_COMMAND: "sendDevToolsCommand", - SEND_AND_GET_DEVTOOLS_COMMAND: "sendAndGetDevToolsCommand", - SET_PERMISSION: "setPermission", - GET_CAST_SINKS: "getCastSinks", - SET_CAST_SINK_TO_USE: "setCastSinkToUse", - START_CAST_DESKTOP_MIRRORING: "startDesktopMirroring", - START_CAST_TAB_MIRRORING: "setCastTabMirroring", - GET_CAST_ISSUE_MESSAGE: "getCastIssueMessage", - STOP_CASTING: "stopCasting" -}; + LAUNCH_APP: 'launchApp', + GET_NETWORK_CONDITIONS: 'getNetworkConditions', + SET_NETWORK_CONDITIONS: 'setNetworkConditions', + DELETE_NETWORK_CONDITIONS: 'deleteNetworkConditions', + SEND_DEVTOOLS_COMMAND: 'sendDevToolsCommand', + SEND_AND_GET_DEVTOOLS_COMMAND: 'sendAndGetDevToolsCommand', + SET_PERMISSION: 'setPermission', + GET_CAST_SINKS: 'getCastSinks', + SET_CAST_SINK_TO_USE: 'setCastSinkToUse', + START_CAST_DESKTOP_MIRRORING: 'startDesktopMirroring', + START_CAST_TAB_MIRRORING: 'setCastTabMirroring', + GET_CAST_ISSUE_MESSAGE: 'getCastIssueMessage', + STOP_CASTING: 'stopCasting', +} /** * Creates a command executor with support for Chromium's custom commands. @@ -108,60 +108,52 @@ const Command = { * @param vendorPrefix * @return {!command.Executor} The new command executor. */ -function createExecutor (url, vendorPrefix) { - const agent = new http.Agent({ keepAlive: true }); - const client = url.then((url) => new http.HttpClient(url, agent)); - const executor = new http.Executor(client); - configureExecutor(executor, vendorPrefix); - return executor; +function createExecutor(url, vendorPrefix) { + const agent = new http.Agent({ keepAlive: true }) + const client = url.then((url) => new http.HttpClient(url, agent)) + const executor = new http.Executor(client) + configureExecutor(executor, vendorPrefix) + return executor } /** * Configures the given executor with Chromium-specific commands. * @param {!http.Executor} executor the executor to configure. */ -function configureExecutor (executor, vendorPrefix) { - 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"); - executor.defineCommand(Command.DELETE_NETWORK_CONDITIONS, "DELETE", - "/session/:sessionId/chromium/network_conditions"); - executor.defineCommand(Command.SEND_DEVTOOLS_COMMAND, "POST", - "/session/:sessionId/chromium/send_command"); - executor.defineCommand( - Command.SEND_AND_GET_DEVTOOLS_COMMAND, - "POST", - "/session/:sessionId/chromium/send_command_and_get_result" - ); - executor.defineCommand(Command.SET_PERMISSION, "POST", - "/session/:sessionId/permissions"); - executor.defineCommand(Command.GET_CAST_SINKS, "GET", - `/session/:sessionId/${vendorPrefix}/cast/get_sinks`); - executor.defineCommand( - Command.SET_CAST_SINK_TO_USE, - "POST", - `/session/:sessionId/${vendorPrefix}/cast/set_sink_to_use` - ); - executor.defineCommand( - Command.START_CAST_DESKTOP_MIRRORING, - "POST", - `/session/:sessionId/${vendorPrefix}/cast/start_desktop_mirroring` - ); - executor.defineCommand( - Command.START_CAST_TAB_MIRRORING, - "POST", - `/session/:sessionId/${vendorPrefix}/cast/start_tab_mirroring` - ); - executor.defineCommand( - Command.GET_CAST_ISSUE_MESSAGE, - "GET", - `/session/:sessionId/${vendorPrefix}/cast/get_issue_message` - ); - executor.defineCommand(Command.STOP_CASTING, "POST", - `/session/:sessionId/${vendorPrefix}/cast/stop_casting`); +function configureExecutor(executor, vendorPrefix) { + 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') + executor.defineCommand(Command.DELETE_NETWORK_CONDITIONS, 'DELETE', '/session/:sessionId/chromium/network_conditions') + executor.defineCommand(Command.SEND_DEVTOOLS_COMMAND, 'POST', '/session/:sessionId/chromium/send_command') + executor.defineCommand( + Command.SEND_AND_GET_DEVTOOLS_COMMAND, + 'POST', + '/session/:sessionId/chromium/send_command_and_get_result', + ) + executor.defineCommand(Command.SET_PERMISSION, 'POST', '/session/:sessionId/permissions') + executor.defineCommand(Command.GET_CAST_SINKS, 'GET', `/session/:sessionId/${vendorPrefix}/cast/get_sinks`) + executor.defineCommand( + Command.SET_CAST_SINK_TO_USE, + 'POST', + `/session/:sessionId/${vendorPrefix}/cast/set_sink_to_use`, + ) + executor.defineCommand( + Command.START_CAST_DESKTOP_MIRRORING, + 'POST', + `/session/:sessionId/${vendorPrefix}/cast/start_desktop_mirroring`, + ) + executor.defineCommand( + Command.START_CAST_TAB_MIRRORING, + 'POST', + `/session/:sessionId/${vendorPrefix}/cast/start_tab_mirroring`, + ) + executor.defineCommand( + Command.GET_CAST_ISSUE_MESSAGE, + 'GET', + `/session/:sessionId/${vendorPrefix}/cast/get_issue_message`, + ) + executor.defineCommand(Command.STOP_CASTING, 'POST', `/session/:sessionId/${vendorPrefix}/cast/stop_casting`) } /** @@ -169,711 +161,695 @@ function configureExecutor (executor, vendorPrefix) { * a WebDriver server in a child process. */ class ServiceBuilder extends remote.DriverService.Builder { - /** - * @param {string=} exe Path to the server executable to use. Subclasses - * should ensure a valid path to the appropriate exe is provided. - */ - constructor (exe) { - super(exe); - this.setLoopback(true); // Required - } - - /** - * Sets which port adb is listening to. _The driver 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 Chrome logging. - * @returns {!ServiceBuilder} A self reference. - */ - enableChromeLogging () { - return this.addArguments("--enable-chrome-logs"); - } - - /** - * 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); - } + /** + * @param {string=} exe Path to the server executable to use. Subclasses + * should ensure a valid path to the appropriate exe is provided. + */ + constructor(exe) { + super(exe) + this.setLoopback(true) // Required + } + + /** + * Sets which port adb is listening to. _The driver 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 Chrome logging. + * @returns {!ServiceBuilder} A self reference. + */ + enableChromeLogging() { + return this.addArguments('--enable-chrome-logs') + } + + /** + * 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) + } } /** * Class for managing WebDriver options specific to a Chromium-based browser. */ class Options extends Capabilities { - /** - * @param {(Capabilities|Map|Object)=} other Another set of - * capabilities to initialize this instance from. - */ - constructor (other = undefined) { - super(other); - - /** @private {!Object} */ - this.options_ = this.get(this.CAPABILITY_KEY) || {}; - - this.setBrowserName(this.BROWSER_NAME_VALUE); - this.set(this.CAPABILITY_KEY, this.options_); - } - - /** - * Add additional command line arguments to use when launching the 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)} 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; - } - - /** - * Sets the address of a Chromium remote debugging server to connect to. - * Address should be of the form "{hostname|IP address}:port" - * (e.g. "localhost:9222"). - * - * @param {string} address The address to connect to. - * @return {!Options} A self reference. - */ - debuggerAddress (address) { - this.options_.debuggerAddress = address; - return this; - } - - /** - * 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)} 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 the browser. 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) { - let extensions = this.options_.extensions || new Extensions(); - extensions.add(...args); - if (extensions.length) { - this.options_.extensions = extensions; - } - return this; - } - - /** - * Sets the path to the browser binary to use. On Mac OS X, this path should - * reference the actual Chromium executable, not just the application binary - * (e.g. "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"). - * - * The binary path can be absolute or relative to the WebDriver server - * executable, but it must exist on the machine that will launch the browser. - * - * @param {string} path The path to the browser binary to use. - * @return {!Options} A self reference. - */ - setBinaryPath (path) { - this.options_.binary = path; - return this; - } - - /** - * Sets whether to leave the started browser process running if the controlling - * driver service is killed before {@link webdriver.WebDriver#quit()} is - * called. - * @param {boolean} detach Whether to leave the browser running if the - * driver 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 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. - * - `traceCategories`: A comma-separated string of Chromium 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, - * traceCategories: 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://chromedriver.chromium.org/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 - * WebDriver server 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; - } - - /** - * 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 browser. - * @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 the browser's log file. This path should exist on the machine - * that will launch the browser. - * @param {string} path Path to the log file to use. - * @return {!Options} A self reference. - */ - setBrowserLogFile (path) { - this.options_.logPath = path; - return this; - } - - /** - * Sets the directory to store browser minidumps in. This option is only - * supported when the driver is running on Linux. - * @param {string} path The directory path. - * @return {!Options} A self reference. - */ - setBrowserMinidumpPath (path) { - this.options_.minidumpPath = path; - return this; - } - - /** - * Configures the browser 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({deviceMetrics: { - * width: 360, - * height: 640, - * pixelRatio: 3.0 - * }}); - * - * let driver = chrome.Driver.createSession(options); - * - * - * [em]: https://chromedriver.chromium.org/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 a list of the window types that will appear when getting window - * handles. For access to elements, include "webview" in the list. - * @param {...(string|!Array)} args The window types that will appear - * when getting window handles. - * @return {!Options} A self reference. - */ - windowTypes (...args) { - let windowTypes = (this.options_.windowTypes || []).concat(...args); - if (windowTypes.length) { - this.options_.windowTypes = windowTypes; - } - return this; - } - - /** - * Enable bidi connection - * @returns {!Capabilities} - */ - enableBidi () { - return this.set("webSocketUrl", true); - } + /** + * @param {(Capabilities|Map|Object)=} other Another set of + * capabilities to initialize this instance from. + */ + constructor(other = undefined) { + super(other) + + /** @private {!Object} */ + this.options_ = this.get(this.CAPABILITY_KEY) || {} + + this.setBrowserName(this.BROWSER_NAME_VALUE) + this.set(this.CAPABILITY_KEY, this.options_) + } + + /** + * Add additional command line arguments to use when launching the 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)} 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 + } + + /** + * Sets the address of a Chromium remote debugging server to connect to. + * Address should be of the form "{hostname|IP address}:port" + * (e.g. "localhost:9222"). + * + * @param {string} address The address to connect to. + * @return {!Options} A self reference. + */ + debuggerAddress(address) { + this.options_.debuggerAddress = address + return this + } + + /** + * 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)} 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 the browser. 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) { + let extensions = this.options_.extensions || new Extensions() + extensions.add(...args) + if (extensions.length) { + this.options_.extensions = extensions + } + return this + } + + /** + * Sets the path to the browser binary to use. On Mac OS X, this path should + * reference the actual Chromium executable, not just the application binary + * (e.g. "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"). + * + * The binary path can be absolute or relative to the WebDriver server + * executable, but it must exist on the machine that will launch the browser. + * + * @param {string} path The path to the browser binary to use. + * @return {!Options} A self reference. + */ + setBinaryPath(path) { + this.options_.binary = path + return this + } + + /** + * Sets whether to leave the started browser process running if the controlling + * driver service is killed before {@link webdriver.WebDriver#quit()} is + * called. + * @param {boolean} detach Whether to leave the browser running if the + * driver 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 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. + * - `traceCategories`: A comma-separated string of Chromium 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, + * traceCategories: 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://chromedriver.chromium.org/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 + * WebDriver server 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 + } + + /** + * 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 browser. + * @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 the browser's log file. This path should exist on the machine + * that will launch the browser. + * @param {string} path Path to the log file to use. + * @return {!Options} A self reference. + */ + setBrowserLogFile(path) { + this.options_.logPath = path + return this + } + + /** + * Sets the directory to store browser minidumps in. This option is only + * supported when the driver is running on Linux. + * @param {string} path The directory path. + * @return {!Options} A self reference. + */ + setBrowserMinidumpPath(path) { + this.options_.minidumpPath = path + return this + } + + /** + * Configures the browser 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({deviceMetrics: { + * width: 360, + * height: 640, + * pixelRatio: 3.0 + * }}); + * + * let driver = chrome.Driver.createSession(options); + * + * + * [em]: https://chromedriver.chromium.org/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 a list of the window types that will appear when getting window + * handles. For access to elements, include "webview" in the list. + * @param {...(string|!Array)} args The window types that will appear + * when getting window handles. + * @return {!Options} A self reference. + */ + windowTypes(...args) { + let windowTypes = (this.options_.windowTypes || []).concat(...args) + if (windowTypes.length) { + this.options_.windowTypes = windowTypes + } + return this + } + + /** + * Enable bidi connection + * @returns {!Capabilities} + */ + enableBidi() { + return this.set('webSocketUrl', true) + } } /** * A list of extensions to install when launching the browser. */ class Extensions { - constructor () { - this.extensions = []; - } - - /** - * @return {number} The length of the extensions list. - */ - get length () { - return this.extensions.length; - } - - /** - * Add additional extensions to install when launching the browser. 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. - */ - add (...args) { - this.extensions = this.extensions.concat(...args); - } - - /** - * @return {!Object} A serialized representation of this Extensions object. - */ - [Symbols.serialize] () { - return this.extensions.map(function(extension) { - if (Buffer.isBuffer(extension)) { - return extension.toString("base64"); - } - return io.read(/** @type {string} */ (extension)).then( - (buffer) => buffer.toString("base64")); - }); - } + constructor() { + this.extensions = [] + } + + /** + * @return {number} The length of the extensions list. + */ + get length() { + return this.extensions.length + } + + /** + * Add additional extensions to install when launching the browser. 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. + */ + add(...args) { + this.extensions = this.extensions.concat(...args) + } + + /** + * @return {!Object} A serialized representation of this Extensions object. + */ + [Symbols.serialize]() { + return this.extensions.map(function (extension) { + if (Buffer.isBuffer(extension)) { + return extension.toString('base64') + } + return io.read(/** @type {string} */ (extension)).then((buffer) => buffer.toString('base64')) + }) + } } /** * Creates a new WebDriver client for Chromium-based browsers. */ class Driver extends webdriver.WebDriver { - /** - * Creates a new session with the WebDriver server. - * - * @param {(Capabilities|Options)=} caps 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 vendorPrefix Either 'goog' or 'ms' - * @param vendorCapabilityKey Either 'goog:chromeOptions' or 'ms:edgeOptions' - * @return {!Driver} A new driver instance. - */ - static createSession (caps, opt_serviceExecutor, vendorPrefix = "", - vendorCapabilityKey = "") { - let executor; - let onQuit; - if (opt_serviceExecutor instanceof http.Executor) { - executor = opt_serviceExecutor; - configureExecutor(executor, vendorPrefix); - } else { - let service = opt_serviceExecutor || this.getDefaultService(); - if (!service.getExecutable()) { - const { driverPath, browserPath } = getBinaryPaths(caps); - service.setExecutable(driverPath); - if (browserPath) { - const vendorOptions = caps.get(vendorCapabilityKey); - if (vendorOptions) { - vendorOptions["binary"] = browserPath; - caps.set(vendorCapabilityKey, vendorOptions); - } else { - caps.set(vendorCapabilityKey, { binary: browserPath }); - } - caps.delete(Capability.BROWSER_VERSION); - } - } - onQuit = () => service.kill(); - executor = createExecutor(service.start(), vendorPrefix); - } - - // W3C spec requires noProxy value to be an array of strings, but Chromium - // expects a single host as a string. - let proxy = caps.get(Capability.PROXY); - if (proxy && Array.isArray(proxy.noProxy)) { - proxy.noProxy = proxy.noProxy[0]; - if (!proxy.noProxy) { - proxy.noProxy = undefined; - } - } - - return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit)); - } - - /** - * 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} A promise that will be resolved - * when app is launched. - */ - launchApp (id) { - return this.execute( - new command.Command(Command.LAUNCH_APP).setParameter("id", id)); - } - - /** - * Schedules a command to get Chromium network emulation settings. - * @return {!Promise} A promise that will be resolved when network - * emulation settings are retrieved. - */ - getNetworkConditions () { - return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS)); - } - - /** - * Schedules a command to delete Chromium network emulation settings. - * @return {!Promise} A promise that will be resolved when network - * emulation settings have been deleted. - */ - deleteNetworkConditions () { - return this.execute(new command.Command(Command.DELETE_NETWORK_CONDITIONS)); - } - - /** - * Schedules a command to set Chromium 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} 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.execute( - new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter( - "network_conditions", spec)); - } - - /** - * Sends an arbitrary devtools command to the browser. - * - * @param {string} cmd The name of the command to send. - * @param {Object=} params The command parameters. - * @return {!Promise} A promise that will be resolved when the command - * has finished. - * @see - */ - sendDevToolsCommand (cmd, params = {}) { - return this.execute( - new command.Command(Command.SEND_DEVTOOLS_COMMAND).setParameter("cmd", - cmd).setParameter("params", params) - ); - } - - /** - * Sends an arbitrary devtools command to the browser and get the result. - * - * @param {string} cmd The name of the command to send. - * @param {Object=} params The command parameters. - * @return {!Promise} A promise that will be resolved when the command - * has finished. - * @see - */ - sendAndGetDevToolsCommand (cmd, params = {}) { - return this.execute( - new command.Command(Command.SEND_AND_GET_DEVTOOLS_COMMAND) - .setParameter("cmd", cmd) - .setParameter("params", params) - ); - } - - /** - * Set a permission state to the given value. - * - * @param {string} name A name of the permission to update. - * @param {("granted"|"denied"|"prompt")} state State to set permission to. - * @returns {!Promise} A promise that will be resolved when the - * command has finished. - * @see for valid - * names - */ - setPermission (name, state) { - return this.execute( - new command.Command(Command.SET_PERMISSION).setParameter("descriptor", - { name }).setParameter("state", state) - ); - } - - /** - * Sends a DevTools command to change the browser's download directory. - * - * @param {string} path The desired download directory. - * @return {!Promise} A promise that will be resolved when the command - * has finished. - * @see #sendDevToolsCommand - */ - async setDownloadPath (path) { - if (!path || typeof path !== "string") { - throw new error.InvalidArgumentError("invalid download path"); - } - const stat = await io.stat(path); - if (!stat.isDirectory()) { - throw new error.InvalidArgumentError("not a directory: " + path); - } - return this.sendDevToolsCommand("Page.setDownloadBehavior", { - behavior: "allow", - downloadPath: path - }); - } - - /** - * Returns the list of cast sinks (Cast devices) available to the Chrome media router. - * - * @return {!promise.Thenable} A promise that will be resolved with an array of Strings - * containing the friendly device names of available cast sink targets. - */ - getCastSinks () { - return this.execute(new command.Command(Command.GET_CAST_SINKS)); - } - - /** - * Selects a cast sink (Cast device) as the recipient of media router intents (connect or play). - * - * @param {String} deviceName name of the target device. - * @return {!promise.Thenable} A promise that will be resolved - * when the target device has been selected to respond further webdriver commands. - */ - setCastSinkToUse (deviceName) { - return this.execute( - new command.Command(Command.SET_CAST_SINK_TO_USE).setParameter("sinkName", - deviceName)); - } - - /** - * Initiates desktop mirroring for the current browser tab on the specified device. - * - * @param {String} deviceName name of the target device. - * @return {!promise.Thenable} A promise that will be resolved - * when the mirror command has been issued to the device. - */ - startDesktopMirroring (deviceName) { - return this.execute( - new command.Command(Command.START_CAST_DESKTOP_MIRRORING).setParameter( - "sinkName", deviceName)); - } - - /** - * Initiates tab mirroring for the current browser tab on the specified device. - * - * @param {String} deviceName name of the target device. - * @return {!promise.Thenable} A promise that will be resolved - * when the mirror command has been issued to the device. - */ - startCastTabMirroring (deviceName) { - return this.execute( - new command.Command(Command.START_CAST_TAB_MIRRORING).setParameter( - "sinkName", deviceName)); - } - - /** - * Returns an error message when there is any issue in a Cast session. - * @return {!promise.Thenable} A promise that will be resolved - * when the mirror command has been issued to the device. - */ - getCastIssueMessage () { - return this.execute(new command.Command(Command.GET_CAST_ISSUE_MESSAGE)); - } - - /** - * Stops casting from media router to the specified device, if connected. - * - * @param {String} deviceName name of the target device. - * @return {!promise.Thenable} A promise that will be resolved - * when the stop command has been issued to the device. - */ - stopCasting (deviceName) { - return this.execute( - new command.Command(Command.STOP_CASTING).setParameter("sinkName", - deviceName)); - } + /** + * Creates a new session with the WebDriver server. + * + * @param {(Capabilities|Options)=} caps 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 vendorPrefix Either 'goog' or 'ms' + * @param vendorCapabilityKey Either 'goog:chromeOptions' or 'ms:edgeOptions' + * @return {!Driver} A new driver instance. + */ + static createSession(caps, opt_serviceExecutor, vendorPrefix = '', vendorCapabilityKey = '') { + let executor + let onQuit + if (opt_serviceExecutor instanceof http.Executor) { + executor = opt_serviceExecutor + configureExecutor(executor, vendorPrefix) + } else { + let service = opt_serviceExecutor || this.getDefaultService() + if (!service.getExecutable()) { + const { driverPath, browserPath } = getBinaryPaths(caps) + service.setExecutable(driverPath) + if (browserPath) { + const vendorOptions = caps.get(vendorCapabilityKey) + if (vendorOptions) { + vendorOptions['binary'] = browserPath + caps.set(vendorCapabilityKey, vendorOptions) + } else { + caps.set(vendorCapabilityKey, { binary: browserPath }) + } + caps.delete(Capability.BROWSER_VERSION) + } + } + onQuit = () => service.kill() + executor = createExecutor(service.start(), vendorPrefix) + } + + // W3C spec requires noProxy value to be an array of strings, but Chromium + // expects a single host as a string. + let proxy = caps.get(Capability.PROXY) + if (proxy && Array.isArray(proxy.noProxy)) { + proxy.noProxy = proxy.noProxy[0] + if (!proxy.noProxy) { + proxy.noProxy = undefined + } + } + + return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit)) + } + + /** + * 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} A promise that will be resolved + * when app is launched. + */ + launchApp(id) { + return this.execute(new command.Command(Command.LAUNCH_APP).setParameter('id', id)) + } + + /** + * Schedules a command to get Chromium network emulation settings. + * @return {!Promise} A promise that will be resolved when network + * emulation settings are retrieved. + */ + getNetworkConditions() { + return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS)) + } + + /** + * Schedules a command to delete Chromium network emulation settings. + * @return {!Promise} A promise that will be resolved when network + * emulation settings have been deleted. + */ + deleteNetworkConditions() { + return this.execute(new command.Command(Command.DELETE_NETWORK_CONDITIONS)) + } + + /** + * Schedules a command to set Chromium 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} 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.execute(new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter('network_conditions', spec)) + } + + /** + * Sends an arbitrary devtools command to the browser. + * + * @param {string} cmd The name of the command to send. + * @param {Object=} params The command parameters. + * @return {!Promise} A promise that will be resolved when the command + * has finished. + * @see + */ + sendDevToolsCommand(cmd, params = {}) { + return this.execute( + new command.Command(Command.SEND_DEVTOOLS_COMMAND).setParameter('cmd', cmd).setParameter('params', params), + ) + } + + /** + * Sends an arbitrary devtools command to the browser and get the result. + * + * @param {string} cmd The name of the command to send. + * @param {Object=} params The command parameters. + * @return {!Promise} A promise that will be resolved when the command + * has finished. + * @see + */ + sendAndGetDevToolsCommand(cmd, params = {}) { + return this.execute( + new command.Command(Command.SEND_AND_GET_DEVTOOLS_COMMAND) + .setParameter('cmd', cmd) + .setParameter('params', params), + ) + } + + /** + * Set a permission state to the given value. + * + * @param {string} name A name of the permission to update. + * @param {("granted"|"denied"|"prompt")} state State to set permission to. + * @returns {!Promise} A promise that will be resolved when the + * command has finished. + * @see for valid + * names + */ + setPermission(name, state) { + return this.execute( + new command.Command(Command.SET_PERMISSION).setParameter('descriptor', { name }).setParameter('state', state), + ) + } + + /** + * Sends a DevTools command to change the browser's download directory. + * + * @param {string} path The desired download directory. + * @return {!Promise} A promise that will be resolved when the command + * has finished. + * @see #sendDevToolsCommand + */ + async setDownloadPath(path) { + if (!path || typeof path !== 'string') { + throw new error.InvalidArgumentError('invalid download path') + } + const stat = await io.stat(path) + if (!stat.isDirectory()) { + throw new error.InvalidArgumentError('not a directory: ' + path) + } + return this.sendDevToolsCommand('Page.setDownloadBehavior', { + behavior: 'allow', + downloadPath: path, + }) + } + + /** + * Returns the list of cast sinks (Cast devices) available to the Chrome media router. + * + * @return {!promise.Thenable} A promise that will be resolved with an array of Strings + * containing the friendly device names of available cast sink targets. + */ + getCastSinks() { + return this.execute(new command.Command(Command.GET_CAST_SINKS)) + } + + /** + * Selects a cast sink (Cast device) as the recipient of media router intents (connect or play). + * + * @param {String} deviceName name of the target device. + * @return {!promise.Thenable} A promise that will be resolved + * when the target device has been selected to respond further webdriver commands. + */ + setCastSinkToUse(deviceName) { + return this.execute(new command.Command(Command.SET_CAST_SINK_TO_USE).setParameter('sinkName', deviceName)) + } + + /** + * Initiates desktop mirroring for the current browser tab on the specified device. + * + * @param {String} deviceName name of the target device. + * @return {!promise.Thenable} A promise that will be resolved + * when the mirror command has been issued to the device. + */ + startDesktopMirroring(deviceName) { + return this.execute(new command.Command(Command.START_CAST_DESKTOP_MIRRORING).setParameter('sinkName', deviceName)) + } + + /** + * Initiates tab mirroring for the current browser tab on the specified device. + * + * @param {String} deviceName name of the target device. + * @return {!promise.Thenable} A promise that will be resolved + * when the mirror command has been issued to the device. + */ + startCastTabMirroring(deviceName) { + return this.execute(new command.Command(Command.START_CAST_TAB_MIRRORING).setParameter('sinkName', deviceName)) + } + + /** + * Returns an error message when there is any issue in a Cast session. + * @return {!promise.Thenable} A promise that will be resolved + * when the mirror command has been issued to the device. + */ + getCastIssueMessage() { + return this.execute(new command.Command(Command.GET_CAST_ISSUE_MESSAGE)) + } + + /** + * Stops casting from media router to the specified device, if connected. + * + * @param {String} deviceName name of the target device. + * @return {!promise.Thenable} A promise that will be resolved + * when the stop command has been issued to the device. + */ + stopCasting(deviceName) { + return this.execute(new command.Command(Command.STOP_CASTING).setParameter('sinkName', deviceName)) + } } // PUBLIC API module.exports = { - Driver, - Options, - ServiceBuilder -}; + Driver, + Options, + ServiceBuilder, +} diff --git a/javascript/node/selenium-webdriver/edge.js b/javascript/node/selenium-webdriver/edge.js index 69e5fc5334066..7b633804f6831 100644 --- a/javascript/node/selenium-webdriver/edge.js +++ b/javascript/node/selenium-webdriver/edge.js @@ -77,11 +77,11 @@ * @module selenium-webdriver/edge */ -"use strict"; +'use strict' -const { Browser } = require("./lib/capabilities"); -const chromium = require("./chromium"); -const EDGE_CAPABILITY_KEY = "ms:edgeOptions"; +const { Browser } = require('./lib/capabilities') +const chromium = require('./chromium') +const EDGE_CAPABILITY_KEY = 'ms:edgeOptions' /** @type {remote.DriverService} */ @@ -91,91 +91,90 @@ const EDGE_CAPABILITY_KEY = "ms:edgeOptions"; * server in a child process. */ class ServiceBuilder extends chromium.ServiceBuilder { - /** - * @param {string=} opt_exe Path to the server executable to use. If omitted, - * the builder will attempt to locate the msedgedriver on the current - * PATH. - * @throws {Error} If provided executable does not exist, or the msedgedriver - * cannot be found on the PATH. - */ - constructor (opt_exe) { - super(opt_exe); - this.setLoopback(true); - } + /** + * @param {string=} opt_exe Path to the server executable to use. If omitted, + * the builder will attempt to locate the msedgedriver on the current + * PATH. + * @throws {Error} If provided executable does not exist, or the msedgedriver + * cannot be found on the PATH. + */ + constructor(opt_exe) { + super(opt_exe) + this.setLoopback(true) + } } /** * Class for managing edge chromium specific options. */ class Options extends chromium.Options { - /** - * Sets the path to the edge binary to use - * - * The binary path be absolute or relative to the msedgedriver server - * executable, but it must exist on the machine that will launch edge chromium. - * - * @param {string} path The path to the msedgedriver binary to use. - * @return {!Options} A self reference. - */ - setEdgeChromiumBinaryPath (path) { - return this.setBinaryPath(path); - } + /** + * Sets the path to the edge binary to use + * + * The binary path be absolute or relative to the msedgedriver server + * executable, but it must exist on the machine that will launch edge chromium. + * + * @param {string} path The path to the msedgedriver binary to use. + * @return {!Options} A self reference. + */ + setEdgeChromiumBinaryPath(path) { + return this.setBinaryPath(path) + } - /** - * Changes the browser name to 'webview2' to enable - * - * test automation of WebView2 apps with Microsoft Edge WebDriver - * - * - * @param {boolean} enable flag to enable or disable the 'webview2' usage - */ - useWebView (enable) { - const browserName = enable ? "webview2" : Browser.EDGE; - return this.setBrowserName(browserName); - } + /** + * Changes the browser name to 'webview2' to enable + * + * test automation of WebView2 apps with Microsoft Edge WebDriver + * + * + * @param {boolean} enable flag to enable or disable the 'webview2' usage + */ + useWebView(enable) { + const browserName = enable ? 'webview2' : Browser.EDGE + return this.setBrowserName(browserName) + } } /** * Creates a new WebDriver client for Microsoft's Edge. */ class Driver extends chromium.Driver { - /** - * Creates a new browser session for Microsoft's Edge browser. - * - * @param {(Capabilities|Options)=} opt_config The configuration options. - * @param {remote.DriverService=} opt_serviceExecutor The service to use; will create - * a new Legacy or Chromium service based on {@linkplain Options} by default. - * @return {!Driver} A new driver instance. - */ - static createSession (opt_config, opt_serviceExecutor) { - let caps = opt_config || new Options(); - return /** @type {!Driver} */ (super.createSession(caps, - opt_serviceExecutor, "ms", EDGE_CAPABILITY_KEY)); - } + /** + * Creates a new browser session for Microsoft's Edge browser. + * + * @param {(Capabilities|Options)=} opt_config The configuration options. + * @param {remote.DriverService=} opt_serviceExecutor The service to use; will create + * a new Legacy or Chromium service based on {@linkplain Options} by default. + * @return {!Driver} A new driver instance. + */ + static createSession(opt_config, opt_serviceExecutor) { + let caps = opt_config || new Options() + return /** @type {!Driver} */ (super.createSession(caps, opt_serviceExecutor, 'ms', EDGE_CAPABILITY_KEY)) + } - /** - * returns new instance of edge driver service - * @returns {remote.DriverService} - */ - static getDefaultService () { - return new ServiceBuilder().build(); - } + /** + * returns new instance of edge driver service + * @returns {remote.DriverService} + */ + static getDefaultService() { + return new ServiceBuilder().build() + } - /** - * This function is a no-op as file detectors are not supported by this - * implementation. - * @override - */ - setFileDetector () {} + /** + * This function is a no-op as file detectors are not supported by this + * implementation. + * @override + */ + setFileDetector() {} } -Options.prototype.BROWSER_NAME_VALUE = Browser.EDGE; -Options.prototype.CAPABILITY_KEY = EDGE_CAPABILITY_KEY; +Options.prototype.BROWSER_NAME_VALUE = Browser.EDGE +Options.prototype.CAPABILITY_KEY = EDGE_CAPABILITY_KEY // PUBLIC API module.exports = { - Driver, - Options, - ServiceBuilder -}; + Driver, + Options, + ServiceBuilder, +} diff --git a/javascript/node/selenium-webdriver/firefox.js b/javascript/node/selenium-webdriver/firefox.js index 8f3238cb19c37..d3fd0c60e9280 100644 --- a/javascript/node/selenium-webdriver/firefox.js +++ b/javascript/node/selenium-webdriver/firefox.js @@ -107,33 +107,33 @@ * @module selenium-webdriver/firefox */ -"use strict"; - -const fs = require("node:fs"); -const path = require("node:path"); -const Symbols = require("./lib/symbols"); -const command = require("./lib/command"); -const http = require("./http"); -const io = require("./io"); -const remote = require("./remote"); -const webdriver = require("./lib/webdriver"); -const zip = require("./io/zip"); -const { Browser, Capabilities, Capability } = require("./lib/capabilities"); -const { Zip } = require("./io/zip"); -const { getBinaryPaths } = require("./common/driverFinder"); -const FIREFOX_CAPABILITY_KEY = "moz:firefoxOptions"; +'use strict' + +const fs = require('node:fs') +const path = require('node:path') +const Symbols = require('./lib/symbols') +const command = require('./lib/command') +const http = require('./http') +const io = require('./io') +const remote = require('./remote') +const webdriver = require('./lib/webdriver') +const zip = require('./io/zip') +const { Browser, Capabilities, Capability } = require('./lib/capabilities') +const { Zip } = require('./io/zip') +const { getBinaryPaths } = require('./common/driverFinder') +const FIREFOX_CAPABILITY_KEY = 'moz:firefoxOptions' /** * Thrown when there an add-on is malformed. * @final */ class AddonFormatError extends Error { - /** @param {string} msg The error message. */ - constructor (msg) { - super(msg); - /** @override */ - this.name = this.constructor.name; - } + /** @param {string} msg The error message. */ + constructor(msg) { + super(msg) + /** @override */ + this.name = this.constructor.name + } } /** @@ -143,66 +143,66 @@ class AddonFormatError extends Error { * @return {!Promise} A promise for the add-on ID once * installed. */ -async function installExtension (extension, dir) { - const ext = extension.slice(-4); - if (ext !== ".xpi" && ext !== ".zip") { - throw Error("File name does not end in \".zip\" or \".xpi\": " + ext); - } - - let archive = await zip.load(extension); - if (!archive.has("manifest.json")) { - throw new AddonFormatError(`Couldn't find manifest.json in ${extension}`); - } - - let buf = await archive.getFile("manifest.json"); - let parsedJSON = JSON.parse(buf.toString("utf8")); - - let { browser_specific_settings } = - /** @type {{browser_specific_settings:{gecko:{id:string}}}} */ - parsedJSON; - - if (browser_specific_settings && browser_specific_settings.gecko) { - /* browser_specific_settings is an alternative to applications - * It is meant to facilitate cross-browser plugins since Firefox48 - * see https://bugzilla.mozilla.org/show_bug.cgi?id=1262005 - */ - parsedJSON.applications = browser_specific_settings; - } - - let { applications } = - /** @type {{applications:{gecko:{id:string}}}} */ - parsedJSON; - if (!(applications && applications.gecko && applications.gecko.id)) { - throw new AddonFormatError(`Could not find add-on ID for ${extension}`); - } - - await io.copy(extension, `${path.join(dir, applications.gecko.id)}.xpi`); - return applications.gecko.id; +async function installExtension(extension, dir) { + const ext = extension.slice(-4) + if (ext !== '.xpi' && ext !== '.zip') { + throw Error('File name does not end in ".zip" or ".xpi": ' + ext) + } + + let archive = await zip.load(extension) + if (!archive.has('manifest.json')) { + throw new AddonFormatError(`Couldn't find manifest.json in ${extension}`) + } + + let buf = await archive.getFile('manifest.json') + let parsedJSON = JSON.parse(buf.toString('utf8')) + + let { browser_specific_settings } = + /** @type {{browser_specific_settings:{gecko:{id:string}}}} */ + parsedJSON + + if (browser_specific_settings && browser_specific_settings.gecko) { + /* browser_specific_settings is an alternative to applications + * It is meant to facilitate cross-browser plugins since Firefox48 + * see https://bugzilla.mozilla.org/show_bug.cgi?id=1262005 + */ + parsedJSON.applications = browser_specific_settings + } + + let { applications } = + /** @type {{applications:{gecko:{id:string}}}} */ + parsedJSON + if (!(applications && applications.gecko && applications.gecko.id)) { + throw new AddonFormatError(`Could not find add-on ID for ${extension}`) + } + + await io.copy(extension, `${path.join(dir, applications.gecko.id)}.xpi`) + return applications.gecko.id } class Profile { - constructor () { - /** @private {?string} */ - this.template_ = null; - - /** @private {!Array} */ - this.extensions_ = []; - } - - addExtensions (/** !Array */ paths) { - this.extensions_ = this.extensions_.concat(...paths); - } - - /** - * @return {(!Promise|undefined)} a promise for a base64 encoded - * profile, or undefined if there's no data to include. - */ - [Symbols.serialize] () { - if (this.template_ || this.extensions_.length) { - return buildProfile(this.template_, this.extensions_); - } - return undefined; - } + constructor() { + /** @private {?string} */ + this.template_ = null + + /** @private {!Array} */ + this.extensions_ = [] + } + + addExtensions(/** !Array */ paths) { + this.extensions_ = this.extensions_.concat(...paths) + } + + /** + * @return {(!Promise|undefined)} a promise for a base64 encoded + * profile, or undefined if there's no data to include. + */ + [Symbols.serialize]() { + if (this.template_ || this.extensions_.length) { + return buildProfile(this.template_, this.extensions_) + } + return undefined + } } /** @@ -211,202 +211,198 @@ class Profile { * profile. * @return {!Promise} a promise for the base64 encoded profile. */ -async function buildProfile (template, extensions) { - let dir = template; - - if (extensions.length) { - dir = await io.tmpDir(); - if (template) { - await io.copyDir(/** @type {string} */ (template), dir, - /(parent\.lock|lock|\.parentlock)/); - } - - const extensionsDir = path.join(dir, "extensions"); - await io.mkdir(extensionsDir); - - for (let i = 0; i < extensions.length; i++) { - await installExtension(extensions[i], extensionsDir); - } - } - - let zip = new Zip(); - return zip - .addDir(dir) - .then(() => zip.toBuffer()) - .then((buf) => buf.toString("base64")); +async function buildProfile(template, extensions) { + let dir = template + + if (extensions.length) { + dir = await io.tmpDir() + if (template) { + await io.copyDir(/** @type {string} */ (template), dir, /(parent\.lock|lock|\.parentlock)/) + } + + const extensionsDir = path.join(dir, 'extensions') + await io.mkdir(extensionsDir) + + for (let i = 0; i < extensions.length; i++) { + await installExtension(extensions[i], extensionsDir) + } + } + + let zip = new Zip() + return zip + .addDir(dir) + .then(() => zip.toBuffer()) + .then((buf) => buf.toString('base64')) } /** * Configuration options for the FirefoxDriver. */ class Options extends Capabilities { - /** - * @param {(Capabilities|Map|Object)=} other Another set of - * capabilities to initialize this instance from. - */ - constructor (other) { - super(other); - this.setBrowserName(Browser.FIREFOX); - } - - /** - * @return {!Object} - * @private - */ - firefoxOptions_ () { - let options = this.get(FIREFOX_CAPABILITY_KEY); - if (!options) { - options = {}; - this.set(FIREFOX_CAPABILITY_KEY, options); - } - return options; - } - - /** - * @return {!Profile} - * @private - */ - profile_ () { - let options = this.firefoxOptions_(); - if (!options.profile) { - options.profile = new Profile(); - } - return options.profile; - } - - /** - * Specify additional command line arguments that should be used when starting - * the Firefox browser. - * - * @param {...(string|!Array)} args The arguments to include. - * @return {!Options} A self reference. - */ - addArguments (...args) { - if (args.length) { - let options = this.firefoxOptions_(); - options.args = options.args ? options.args.concat(...args) : args; - } - return this; - } - - /** - * 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(`--width=${width}`, `--height=${height}`); - } - - /** - * Add extensions that should be installed when starting Firefox. - * - * @param {...string} paths The paths to the extension XPI files to install. - * @return {!Options} A self reference. - */ - addExtensions (...paths) { - this.profile_().addExtensions(paths); - return this; - } - - /** - * @param {string} key the preference key. - * @param {(string|number|boolean)} value the preference value. - * @return {!Options} A self reference. - * @throws {TypeError} if either the key or value has an invalid type. - */ - setPreference (key, value) { - if (typeof key !== "string") { - throw TypeError(`key must be a string, but got ${typeof key}`); - } - if (typeof value !== "string" && typeof value !== "number" && typeof value - !== "boolean") { - throw TypeError( - `value must be a string, number, or boolean, but got ${typeof value}`); - } - let options = this.firefoxOptions_(); - options.prefs = options.prefs || {}; - options.prefs[key] = value; - return this; - } - - /** - * Sets the path to an existing profile to use as a template for new browser - * sessions. This profile will be copied for each new session - changes will - * not be applied to the profile itself. - * - * @param {string} profile The profile to use. - * @return {!Options} A self reference. - * @throws {TypeError} if profile is not a string. - */ - setProfile (profile) { - if (typeof profile !== "string") { - throw TypeError(`profile must be a string, but got ${typeof profile}`); - } - this.profile_().template_ = profile; - return this; - } - - /** - * Sets the binary to use. The binary may be specified as the path to a - * Firefox executable. - * - * @param {(string)} binary The binary to use. - * @return {!Options} A self reference. - * @throws {TypeError} If `binary` is an invalid type. - */ - setBinary (binary) { - if (binary instanceof Channel || typeof binary === "string") { - this.firefoxOptions_().binary = binary; - return this; - } - throw TypeError("binary must be a string path "); - } - - /** - * Enables Mobile start up features - * - * @param {string} androidPackage The package to use - * @return {!Options} A self reference - */ - enableMobile (androidPackage = "org.mozilla.firefox", androidActivity = null, - deviceSerial = null) { - this.firefoxOptions_().androidPackage = androidPackage; - - if (androidActivity) { - this.firefoxOptions_().androidActivity = androidActivity; - } - if (deviceSerial) { - this.firefoxOptions_().deviceSerial = deviceSerial; - } - return this; - } - - /** - * Enables moz:debuggerAddress for firefox cdp - */ - enableDebugger () { - return this.set("moz:debuggerAddress", true); - } - - /** - * Enable bidi connection - * @returns {!Capabilities} - */ - enableBidi () { - return this.set("webSocketUrl", true); - } + /** + * @param {(Capabilities|Map|Object)=} other Another set of + * capabilities to initialize this instance from. + */ + constructor(other) { + super(other) + this.setBrowserName(Browser.FIREFOX) + } + + /** + * @return {!Object} + * @private + */ + firefoxOptions_() { + let options = this.get(FIREFOX_CAPABILITY_KEY) + if (!options) { + options = {} + this.set(FIREFOX_CAPABILITY_KEY, options) + } + return options + } + + /** + * @return {!Profile} + * @private + */ + profile_() { + let options = this.firefoxOptions_() + if (!options.profile) { + options.profile = new Profile() + } + return options.profile + } + + /** + * Specify additional command line arguments that should be used when starting + * the Firefox browser. + * + * @param {...(string|!Array)} args The arguments to include. + * @return {!Options} A self reference. + */ + addArguments(...args) { + if (args.length) { + let options = this.firefoxOptions_() + options.args = options.args ? options.args.concat(...args) : args + } + return this + } + + /** + * 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(`--width=${width}`, `--height=${height}`) + } + + /** + * Add extensions that should be installed when starting Firefox. + * + * @param {...string} paths The paths to the extension XPI files to install. + * @return {!Options} A self reference. + */ + addExtensions(...paths) { + this.profile_().addExtensions(paths) + return this + } + + /** + * @param {string} key the preference key. + * @param {(string|number|boolean)} value the preference value. + * @return {!Options} A self reference. + * @throws {TypeError} if either the key or value has an invalid type. + */ + setPreference(key, value) { + if (typeof key !== 'string') { + throw TypeError(`key must be a string, but got ${typeof key}`) + } + if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') { + throw TypeError(`value must be a string, number, or boolean, but got ${typeof value}`) + } + let options = this.firefoxOptions_() + options.prefs = options.prefs || {} + options.prefs[key] = value + return this + } + + /** + * Sets the path to an existing profile to use as a template for new browser + * sessions. This profile will be copied for each new session - changes will + * not be applied to the profile itself. + * + * @param {string} profile The profile to use. + * @return {!Options} A self reference. + * @throws {TypeError} if profile is not a string. + */ + setProfile(profile) { + if (typeof profile !== 'string') { + throw TypeError(`profile must be a string, but got ${typeof profile}`) + } + this.profile_().template_ = profile + return this + } + + /** + * Sets the binary to use. The binary may be specified as the path to a + * Firefox executable. + * + * @param {(string)} binary The binary to use. + * @return {!Options} A self reference. + * @throws {TypeError} If `binary` is an invalid type. + */ + setBinary(binary) { + if (binary instanceof Channel || typeof binary === 'string') { + this.firefoxOptions_().binary = binary + return this + } + throw TypeError('binary must be a string path ') + } + + /** + * Enables Mobile start up features + * + * @param {string} androidPackage The package to use + * @return {!Options} A self reference + */ + enableMobile(androidPackage = 'org.mozilla.firefox', androidActivity = null, deviceSerial = null) { + this.firefoxOptions_().androidPackage = androidPackage + + if (androidActivity) { + this.firefoxOptions_().androidActivity = androidActivity + } + if (deviceSerial) { + this.firefoxOptions_().deviceSerial = deviceSerial + } + return this + } + + /** + * Enables moz:debuggerAddress for firefox cdp + */ + enableDebugger() { + return this.set('moz:debuggerAddress', true) + } + + /** + * Enable bidi connection + * @returns {!Capabilities} + */ + enableBidi() { + return this.set('webSocketUrl', true) + } } /** @@ -420,9 +416,9 @@ class Options extends Capabilities { * @enum {string} */ const Context = { - CONTENT: "content", - CHROME: "chrome" -}; + CONTENT: 'content', + CHROME: 'chrome', +} /** * @param {string} file Path to the file to find, relative to the program files @@ -430,60 +426,55 @@ const Context = { * @return {!Promise} 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; - }); - }); +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 + }) + }) } /** @enum {string} */ const ExtensionCommand = { - GET_CONTEXT: "getContext", - SET_CONTEXT: "setContext", - INSTALL_ADDON: "install addon", - UNINSTALL_ADDON: "uninstall addon", - FULL_PAGE_SCREENSHOT: "fullPage screenshot" -}; + GET_CONTEXT: 'getContext', + SET_CONTEXT: 'setContext', + INSTALL_ADDON: 'install addon', + UNINSTALL_ADDON: 'uninstall addon', + FULL_PAGE_SCREENSHOT: 'fullPage screenshot', +} /** * Creates a command executor with support for Marionette's custom commands. * @param {!Promise} 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; +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"); +function configureExecutor(executor) { + executor.defineCommand(ExtensionCommand.GET_CONTEXT, 'GET', '/session/:sessionId/moz/context') - executor.defineCommand(ExtensionCommand.SET_CONTEXT, "POST", - "/session/:sessionId/moz/context"); + executor.defineCommand(ExtensionCommand.SET_CONTEXT, 'POST', '/session/:sessionId/moz/context') - executor.defineCommand(ExtensionCommand.INSTALL_ADDON, "POST", - "/session/:sessionId/moz/addon/install"); + executor.defineCommand(ExtensionCommand.INSTALL_ADDON, 'POST', '/session/:sessionId/moz/addon/install') - executor.defineCommand(ExtensionCommand.UNINSTALL_ADDON, "POST", - "/session/:sessionId/moz/addon/uninstall"); + executor.defineCommand(ExtensionCommand.UNINSTALL_ADDON, 'POST', '/session/:sessionId/moz/addon/uninstall') - executor.defineCommand(ExtensionCommand.FULL_PAGE_SCREENSHOT, "GET", - "/session/:sessionId/moz/screenshot/full"); + executor.defineCommand(ExtensionCommand.FULL_PAGE_SCREENSHOT, 'GET', '/session/:sessionId/moz/screenshot/full') } /** @@ -492,190 +483,184 @@ function configureExecutor (executor) { * 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); - 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"); - } + /** + * @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) + 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|Object)=} opt_config The - * configuration options for this driver, specified as either an - * {@link Options} or {@link 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._ - * - * @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) { - let caps = opt_config instanceof Capabilities ? opt_config : new Options( - opt_config); - - let firefoxBrowserPath = null; - - let executor; - let onQuit; - - if (opt_executor instanceof http.Executor) { - executor = opt_executor; - configureExecutor(executor); - } else if (opt_executor instanceof remote.DriverService) { - if (!opt_executor.getExecutable()) { - const { driverPath, browserPath } = getBinaryPaths(caps); - opt_executor.setExecutable(driverPath); - firefoxBrowserPath = browserPath; - } - executor = createExecutor(opt_executor.start()); - onQuit = () => opt_executor.kill(); - } else { - let service = new ServiceBuilder().build(); - if (!service.getExecutable()) { - const { driverPath, browserPath } = getBinaryPaths(caps); - service.setExecutable(driverPath); - firefoxBrowserPath = browserPath; - } - executor = createExecutor(service.start()); - onQuit = () => service.kill(); - } - - if (firefoxBrowserPath) { - const vendorOptions = caps.get(FIREFOX_CAPABILITY_KEY); - if (vendorOptions) { - vendorOptions["binary"] = firefoxBrowserPath; - caps.set(FIREFOX_CAPABILITY_KEY, vendorOptions); - } else { - caps.set(FIREFOX_CAPABILITY_KEY, { binary: firefoxBrowserPath }); - } - caps.delete(Capability.BROWSER_VERSION); - } - - return /** @type {!Driver} */ (super.createSession(executor, caps, 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} Current context. - */ - getContext () { - return this.execute(new command.Command(ExtensionCommand.GET_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} ctx The context to switch to. - */ - setContext (ctx) { - return this.execute( - new command.Command(ExtensionCommand.SET_CONTEXT).setParameter("context", - ctx)); - } - - /** - * Installs a new addon with the current session. This function will return an - * ID that may later be used to {@linkplain #uninstallAddon uninstall} the - * addon. - * - * - * @param {string} path Path on the local filesystem to the web extension to - * install. - * @param {boolean} temporary Flag indicating whether the extension should be - * installed temporarily - gets removed on restart - * @return {!Promise} A promise that will resolve to an ID for the - * newly installed addon. - * @see #uninstallAddon - */ - async installAddon (path, temporary = false) { - let stats = fs.statSync(path); - let buf; - if (stats.isDirectory()) { - let zip = new Zip(); - await zip.addDir(path); - buf = await zip.toBuffer("DEFLATE"); - } else { - buf = await io.read(path); - } - return this.execute( - new command.Command(ExtensionCommand.INSTALL_ADDON) - .setParameter("addon", buf.toString("base64")) - .setParameter("temporary", temporary) - ); - } - - /** - * Uninstalls an addon from the current browser session's profile. - * - * @param {(string|!Promise)} id ID of the addon to uninstall. - * @return {!Promise} A promise that will resolve when the operation has - * completed. - * @see #installAddon - */ - async uninstallAddon (id) { - id = await Promise.resolve(id); - return this.execute( - new command.Command(ExtensionCommand.UNINSTALL_ADDON).setParameter("id", - id)); - } - - /** - * Take full page screenshot of the visible region - * - * @return {!Promise} A promise that will be - * resolved to the screenshot as a base-64 encoded PNG. - */ - takeFullPageScreenshot () { - return this.execute( - new command.Command(ExtensionCommand.FULL_PAGE_SCREENSHOT)); - } + /** + * Creates a new Firefox session. + * + * @param {(Options|Capabilities|Object)=} opt_config The + * configuration options for this driver, specified as either an + * {@link Options} or {@link 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._ + * + * @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) { + let caps = opt_config instanceof Capabilities ? opt_config : new Options(opt_config) + + let firefoxBrowserPath = null + + let executor + let onQuit + + if (opt_executor instanceof http.Executor) { + executor = opt_executor + configureExecutor(executor) + } else if (opt_executor instanceof remote.DriverService) { + if (!opt_executor.getExecutable()) { + const { driverPath, browserPath } = getBinaryPaths(caps) + opt_executor.setExecutable(driverPath) + firefoxBrowserPath = browserPath + } + executor = createExecutor(opt_executor.start()) + onQuit = () => opt_executor.kill() + } else { + let service = new ServiceBuilder().build() + if (!service.getExecutable()) { + const { driverPath, browserPath } = getBinaryPaths(caps) + service.setExecutable(driverPath) + firefoxBrowserPath = browserPath + } + executor = createExecutor(service.start()) + onQuit = () => service.kill() + } + + if (firefoxBrowserPath) { + const vendorOptions = caps.get(FIREFOX_CAPABILITY_KEY) + if (vendorOptions) { + vendorOptions['binary'] = firefoxBrowserPath + caps.set(FIREFOX_CAPABILITY_KEY, vendorOptions) + } else { + caps.set(FIREFOX_CAPABILITY_KEY, { binary: firefoxBrowserPath }) + } + caps.delete(Capability.BROWSER_VERSION) + } + + return /** @type {!Driver} */ (super.createSession(executor, caps, 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} Current context. + */ + getContext() { + return this.execute(new command.Command(ExtensionCommand.GET_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} ctx The context to switch to. + */ + setContext(ctx) { + return this.execute(new command.Command(ExtensionCommand.SET_CONTEXT).setParameter('context', ctx)) + } + + /** + * Installs a new addon with the current session. This function will return an + * ID that may later be used to {@linkplain #uninstallAddon uninstall} the + * addon. + * + * + * @param {string} path Path on the local filesystem to the web extension to + * install. + * @param {boolean} temporary Flag indicating whether the extension should be + * installed temporarily - gets removed on restart + * @return {!Promise} A promise that will resolve to an ID for the + * newly installed addon. + * @see #uninstallAddon + */ + async installAddon(path, temporary = false) { + let stats = fs.statSync(path) + let buf + if (stats.isDirectory()) { + let zip = new Zip() + await zip.addDir(path) + buf = await zip.toBuffer('DEFLATE') + } else { + buf = await io.read(path) + } + return this.execute( + new command.Command(ExtensionCommand.INSTALL_ADDON) + .setParameter('addon', buf.toString('base64')) + .setParameter('temporary', temporary), + ) + } + + /** + * Uninstalls an addon from the current browser session's profile. + * + * @param {(string|!Promise)} id ID of the addon to uninstall. + * @return {!Promise} A promise that will resolve when the operation has + * completed. + * @see #installAddon + */ + async uninstallAddon(id) { + id = await Promise.resolve(id) + return this.execute(new command.Command(ExtensionCommand.UNINSTALL_ADDON).setParameter('id', id)) + } + + /** + * Take full page screenshot of the visible region + * + * @return {!Promise} A promise that will be + * resolved to the screenshot as a base-64 encoded PNG. + */ + takeFullPageScreenshot() { + return this.execute(new command.Command(ExtensionCommand.FULL_PAGE_SCREENSHOT)) + } } /** @@ -688,64 +673,60 @@ class Driver extends webdriver.WebDriver { * @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} */ - 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} 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_; - } - - /** @return {!Promise} */ - [Symbols.serialize] () { - return this.locate(); - } + /** + * @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} */ + 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} 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_ + } + + /** @return {!Promise} */ + [Symbols.serialize]() { + return this.locate() + } } /** @@ -754,9 +735,9 @@ class Channel { * @see */ Channel.DEV = new Channel( - "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox", - "Firefox Developer Edition\\firefox.exe" -); + '/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox', + 'Firefox Developer Edition\\firefox.exe', +) /** * Firefox's beta channel. Note this is provided mainly for convenience as @@ -765,34 +746,28 @@ Channel.DEV = new Channel( * @const * @see */ -Channel.BETA = - new Channel("/Applications/Firefox.app/Contents/MacOS/firefox", - "Mozilla Firefox\\firefox.exe"); +Channel.BETA = new Channel('/Applications/Firefox.app/Contents/MacOS/firefox', 'Mozilla Firefox\\firefox.exe') /** * Firefox's release channel. * @const * @see */ -Channel.RELEASE = - new Channel("/Applications/Firefox.app/Contents/MacOS/firefox", - "Mozilla Firefox\\firefox.exe"); +Channel.RELEASE = new Channel('/Applications/Firefox.app/Contents/MacOS/firefox', 'Mozilla Firefox\\firefox.exe') /** * Firefox's nightly release channel. * @const * @see */ -Channel.NIGHTLY = - new Channel("/Applications/Firefox Nightly.app/Contents/MacOS/firefox", - "Nightly\\firefox.exe"); +Channel.NIGHTLY = new Channel('/Applications/Firefox Nightly.app/Contents/MacOS/firefox', 'Nightly\\firefox.exe') // PUBLIC API module.exports = { - Channel, - Context, - Driver, - Options, - ServiceBuilder -}; + Channel, + Context, + Driver, + Options, + ServiceBuilder, +} diff --git a/javascript/node/selenium-webdriver/ie.js b/javascript/node/selenium-webdriver/ie.js index f3cb17683a81c..d4615d49a38bd 100644 --- a/javascript/node/selenium-webdriver/ie.js +++ b/javascript/node/selenium-webdriver/ie.js @@ -27,34 +27,34 @@ * @module selenium-webdriver/ie */ -"use strict"; +'use strict' -const http = require("./http"); -const portprober = require("./net/portprober"); -const remote = require("./remote"); -const webdriver = require("./lib/webdriver"); -const { Browser, Capabilities } = require("./lib/capabilities"); -const error = require("./lib/error"); -const { getBinaryPaths } = require("./common/driverFinder"); +const http = require('./http') +const portprober = require('./net/portprober') +const remote = require('./remote') +const webdriver = require('./lib/webdriver') +const { Browser, Capabilities } = require('./lib/capabilities') +const error = require('./lib/error') +const { getBinaryPaths } = require('./common/driverFinder') -const OPTIONS_CAPABILITY_KEY = "se:ieOptions"; +const OPTIONS_CAPABILITY_KEY = 'se:ieOptions' const SCROLL_BEHAVIOUR = { - BOTTOM: 1, - TOP: 0 -}; + BOTTOM: 1, + TOP: 0, +} /** * IEDriverServer logging levels. * @enum {string} */ const Level = { - FATAL: "FATAL", - ERROR: "ERROR", - WARN: "WARN", - INFO: "INFO", - DEBUG: "DEBUG", - TRACE: "TRACE" -}; + FATAL: 'FATAL', + ERROR: 'ERROR', + WARN: 'WARN', + INFO: 'INFO', + DEBUG: 'DEBUG', + TRACE: 'TRACE', +} /** * Option keys: @@ -62,359 +62,356 @@ const Level = { * @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", - ELEMENT_SCROLL_BEHAVIOR: "elementScrollBehavior", - 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", - FILE_UPLOAD_DIALOG_TIMEOUT: "ie.fileUploadDialogTimeout", - ATTACH_TO_EDGE_CHROMIUM: "ie.edgechromium", - EDGE_EXECUTABLE_PATH: "ie.edgepath", - IGNORE_PROCESS_MATCH: "ie.ignoreprocessmatch" -}; + IGNORE_PROTECTED_MODE_SETTINGS: 'ignoreProtectedModeSettings', + IGNORE_ZOOM_SETTING: 'ignoreZoomSetting', + INITIAL_BROWSER_URL: 'initialBrowserUrl', + ENABLE_PERSISTENT_HOVER: 'enablePersistentHover', + ENABLE_ELEMENT_CACHE_CLEANUP: 'enableElementCacheCleanup', + ELEMENT_SCROLL_BEHAVIOR: 'elementScrollBehavior', + 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', + FILE_UPLOAD_DIALOG_TIMEOUT: 'ie.fileUploadDialogTimeout', + ATTACH_TO_EDGE_CHROMIUM: 'ie.edgechromium', + EDGE_EXECUTABLE_PATH: 'ie.edgepath', + IGNORE_PROCESS_MATCH: 'ie.ignoreprocessmatch', +} /** * Class for managing IEDriver specific options. */ class Options extends Capabilities { - /** - * @param {(Capabilities|Map|Object)=} other Another set of - * capabilities to initialize this instance from. - */ - constructor (other = undefined) { - super(other); - - /** @private {!Object} */ - this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {}; - - this.set(OPTIONS_CAPABILITY_KEY, this.options_); - this.setBrowserName(Browser.INTERNET_EXPLORER); - } - - /** - * Whether to disable the protected mode settings check when the session is - * created. Disabling 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 #introduceFlakinessByIgnoringProtectedModeSettings} 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.)} args The arguments to add. - * @return {!Options} A self reference. - */ - - addBrowserCommandSwitches (...args) { - let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || []; - if (typeof current == "string") { - current = current.split(" "); - } - this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = - current.concat(args).join(" "); - return this; - } - - /** - * Specifies command-line switches to use when launching Internet Explorer. - * This is only valid when used with {@link #forceCreateProcessApi}. - * - * @param {...(string|!Array.)} args The arguments to add. - * @deprecated Use {@link #addBrowserCommandSwitches} instead. - * @return {!Options} A self reference. - */ - - addArguments (...args) { - let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || []; - if (typeof current == "string") { - current = current.split(" "); - } - this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = - current.concat(args).join(" "); - 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; - } - - /** - * The options File Upload Dialog Timeout in milliseconds - * - * @param {number} timeout How long to wait for IE. - * @return {!Options} A self reference. - */ - fileUploadDialogTimeout (timeout) { - this.options_[Key.FILE_UPLOAD_DIALOG_TIMEOUT] = Math.max(timeout, 0); - return this; - } - - /** - * Sets the path of the EdgeChromium driver. - * @param {string} path The EdgeChromium driver path. - * @return {!Options} A self reference. - */ - setEdgePath (path) { - this.options_[Key.EDGE_EXECUTABLE_PATH] = path; - return this; - } - - /** - * Sets the IEDriver to drive Chromium-based Edge in Internet Explorer mode. - * - * @param {boolean} attachEdgeChromium Whether to run in Chromium-based-Edge in IE mode - * @return {!Options} A self reference. - */ - setEdgeChromium (attachEdgeChromium) { - this.options_[Key.ATTACH_TO_EDGE_CHROMIUM] = !!attachEdgeChromium; - 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 {!Options} A self reference. - */ - setScrollBehavior (behavior) { - if (behavior && behavior !== SCROLL_BEHAVIOUR.TOP && behavior - !== SCROLL_BEHAVIOUR.BOTTOM) { - throw new error.InvalidArgumentError(`Element Scroll Behavior out of range. - It should be either ${SCROLL_BEHAVIOUR.TOP} or ${SCROLL_BEHAVIOUR.BOTTOM}`); - } - this.options_[Key.ELEMENT_SCROLL_BEHAVIOR] = behavior; - return this; - } + /** + * @param {(Capabilities|Map|Object)=} other Another set of + * capabilities to initialize this instance from. + */ + constructor(other = undefined) { + super(other) + + /** @private {!Object} */ + this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {} + + this.set(OPTIONS_CAPABILITY_KEY, this.options_) + this.setBrowserName(Browser.INTERNET_EXPLORER) + } + + /** + * Whether to disable the protected mode settings check when the session is + * created. Disabling 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 #introduceFlakinessByIgnoringProtectedModeSettings} 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.)} args The arguments to add. + * @return {!Options} A self reference. + */ + + addBrowserCommandSwitches(...args) { + let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || [] + if (typeof current == 'string') { + current = current.split(' ') + } + this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = current.concat(args).join(' ') + return this + } + + /** + * Specifies command-line switches to use when launching Internet Explorer. + * This is only valid when used with {@link #forceCreateProcessApi}. + * + * @param {...(string|!Array.)} args The arguments to add. + * @deprecated Use {@link #addBrowserCommandSwitches} instead. + * @return {!Options} A self reference. + */ + + addArguments(...args) { + let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || [] + if (typeof current == 'string') { + current = current.split(' ') + } + this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = current.concat(args).join(' ') + 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 + } + + /** + * The options File Upload Dialog Timeout in milliseconds + * + * @param {number} timeout How long to wait for IE. + * @return {!Options} A self reference. + */ + fileUploadDialogTimeout(timeout) { + this.options_[Key.FILE_UPLOAD_DIALOG_TIMEOUT] = Math.max(timeout, 0) + return this + } + + /** + * Sets the path of the EdgeChromium driver. + * @param {string} path The EdgeChromium driver path. + * @return {!Options} A self reference. + */ + setEdgePath(path) { + this.options_[Key.EDGE_EXECUTABLE_PATH] = path + return this + } + + /** + * Sets the IEDriver to drive Chromium-based Edge in Internet Explorer mode. + * + * @param {boolean} attachEdgeChromium Whether to run in Chromium-based-Edge in IE mode + * @return {!Options} A self reference. + */ + setEdgeChromium(attachEdgeChromium) { + this.options_[Key.ATTACH_TO_EDGE_CHROMIUM] = !!attachEdgeChromium + 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 {!Options} A self reference. + */ + setScrollBehavior(behavior) { + if (behavior && behavior !== SCROLL_BEHAVIOUR.TOP && behavior !== SCROLL_BEHAVIOUR.BOTTOM) { + throw new error.InvalidArgumentError(`Element Scroll Behavior out of range. + It should be either ${SCROLL_BEHAVIOUR.TOP} or ${SCROLL_BEHAVIOUR.BOTTOM}`) + } + this.options_[Key.ELEMENT_SCROLL_BEHAVIOR] = behavior + return this + } } -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 = null; // Let Selenium Manager find it - 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" - }); +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 = null // Let Selenium Manager find it + 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', + }) } /** @@ -423,63 +420,62 @@ function createServiceFromCapabilities (capabilities) { * 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 IEDriverServer on the system PATH. - */ - constructor (opt_exe) { - super(opt_exe); - this.setLoopback(true); // Required. - } + /** + * @param {string=} opt_exe Path to the server executable to use. If omitted, + * the builder will attempt to locate the IEDriverServer on the system PATH. + */ + constructor(opt_exe) { + super(opt_exe) + this.setLoopback(true) // Required. + } } /** * A WebDriver client for Microsoft's Internet Explorer. */ class Driver extends webdriver.WebDriver { - /** - * Creates a new session for Microsoft's Internet Explorer. - * - * @param {(Capabilities|Options)=} options The configuration options. - * @param {(remote.DriverService)=} opt_service The `DriverService` to use - * to start the IEDriverServer in a child process, optionally. - * @return {!Driver} A new driver instance. - */ - static createSession (options, opt_service) { - options = options || new Options(); - - let service; - - if (opt_service instanceof remote.DriverService) { - service = opt_service; - } else { - service = createServiceFromCapabilities(options); - } - if (!service.getExecutable()) { - service.setExecutable(getBinaryPaths(options).driverPath); - } - - let client = service.start().then((url) => new http.HttpClient(url)); - let executor = new http.Executor(client); - - return /** @type {!Driver} */ (super.createSession(executor, options, - () => service.kill())); - } - - /** - * This function is a no-op as file detectors are not supported by this - * implementation. - * @override - */ - setFileDetector () {} + /** + * Creates a new session for Microsoft's Internet Explorer. + * + * @param {(Capabilities|Options)=} options The configuration options. + * @param {(remote.DriverService)=} opt_service The `DriverService` to use + * to start the IEDriverServer in a child process, optionally. + * @return {!Driver} A new driver instance. + */ + static createSession(options, opt_service) { + options = options || new Options() + + let service + + if (opt_service instanceof remote.DriverService) { + service = opt_service + } else { + service = createServiceFromCapabilities(options) + } + if (!service.getExecutable()) { + service.setExecutable(getBinaryPaths(options).driverPath) + } + + let client = service.start().then((url) => new http.HttpClient(url)) + let executor = new http.Executor(client) + + return /** @type {!Driver} */ (super.createSession(executor, options, () => 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; -exports.ServiceBuilder = ServiceBuilder; -exports.Key = Key; -exports.VENDOR_COMMAND_PREFIX = OPTIONS_CAPABILITY_KEY; -exports.Behavior = SCROLL_BEHAVIOUR; +exports.Driver = Driver +exports.Options = Options +exports.Level = Level +exports.ServiceBuilder = ServiceBuilder +exports.Key = Key +exports.VENDOR_COMMAND_PREFIX = OPTIONS_CAPABILITY_KEY +exports.Behavior = SCROLL_BEHAVIOUR diff --git a/javascript/node/selenium-webdriver/jsdoc_conf.json b/javascript/node/selenium-webdriver/jsdoc_conf.json index aeae9ba0ca0ad..e639e1e88d9c9 100644 --- a/javascript/node/selenium-webdriver/jsdoc_conf.json +++ b/javascript/node/selenium-webdriver/jsdoc_conf.json @@ -1,14 +1,10 @@ { "source": { - "include": [ - "." - ], + "include": ["."], "includePattern": ".js$", "excludePattern": "(node_modules/|example)" }, - "plugins": [ - "plugins/markdown" - ], + "plugins": ["plugins/markdown"], "opts": { "encoding": "utf8", "readme": "./README.md", diff --git a/javascript/node/selenium-webdriver/safari.js b/javascript/node/selenium-webdriver/safari.js index 05fd0f127559d..9e963f427293a 100644 --- a/javascript/node/selenium-webdriver/safari.js +++ b/javascript/node/selenium-webdriver/safari.js @@ -21,13 +21,13 @@ * @module selenium-webdriver/safari */ -"use strict"; +'use strict' -const http = require("./http"); -const remote = require("./remote"); -const webdriver = require("./lib/webdriver"); -const { Browser, Capabilities } = require("./lib/capabilities"); -const { getBinaryPaths } = require("./common/driverFinder"); +const http = require('./http') +const remote = require('./remote') +const webdriver = require('./lib/webdriver') +const { Browser, Capabilities } = require('./lib/capabilities') +const { getBinaryPaths } = require('./common/driverFinder') /** * Creates {@link remote.DriverService} instances that manage @@ -36,68 +36,68 @@ const { getBinaryPaths } = require("./common/driverFinder"); * [safaridriver]: https://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28 */ 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 safaridriver on the system PATH. - */ - constructor (opt_exe) { - super(opt_exe); - this.setLoopback(true); // Required. - } + /** + * @param {string=} opt_exe Path to the server executable to use. If omitted, + * the builder will attempt to locate the safaridriver on the system PATH. + */ + constructor(opt_exe) { + super(opt_exe) + this.setLoopback(true) // Required. + } } -const OPTIONS_CAPABILITY_KEY = "safari:options"; -const TECHNOLOGY_PREVIEW_OPTIONS_KEY = "technologyPreview"; +const OPTIONS_CAPABILITY_KEY = 'safari:options' +const TECHNOLOGY_PREVIEW_OPTIONS_KEY = 'technologyPreview' /** * Configuration options specific to the {@link Driver SafariDriver}. */ class Options extends Capabilities { - /** - * @param {(Capabilities|Map|Object)=} other Another set of - * capabilities to initialize this instance from. - */ - constructor (other = undefined) { - super(other); - - /** @private {!Object} */ - this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {}; - - this.set(OPTIONS_CAPABILITY_KEY, this.options_); - this.setBrowserName(Browser.SAFARI); - } - - /** - * Instruct the SafariDriver to use the Safari Technology Preview if true. - * Otherwise, use the release version of Safari. Defaults to using the release version of Safari. - * - * @param {boolean} useTechnologyPreview - * @return {!Options} A self reference. - */ - setTechnologyPreview (useTechnologyPreview) { - this.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY] = !!useTechnologyPreview; - return this; - } + /** + * @param {(Capabilities|Map|Object)=} other Another set of + * capabilities to initialize this instance from. + */ + constructor(other = undefined) { + super(other) + + /** @private {!Object} */ + this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {} + + this.set(OPTIONS_CAPABILITY_KEY, this.options_) + this.setBrowserName(Browser.SAFARI) + } + + /** + * Instruct the SafariDriver to use the Safari Technology Preview if true. + * Otherwise, use the release version of Safari. Defaults to using the release version of Safari. + * + * @param {boolean} useTechnologyPreview + * @return {!Options} A self reference. + */ + setTechnologyPreview(useTechnologyPreview) { + this.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY] = !!useTechnologyPreview + return this + } } /** * @param {(Capabilities|Object)=} o The options object * @return {boolean} */ -function useTechnologyPreview (o) { - if (o instanceof Capabilities) { - let options = o.get(OPTIONS_CAPABILITY_KEY); - return !!(options && options[TECHNOLOGY_PREVIEW_OPTIONS_KEY]); - } +function useTechnologyPreview(o) { + if (o instanceof Capabilities) { + let options = o.get(OPTIONS_CAPABILITY_KEY) + return !!(options && options[TECHNOLOGY_PREVIEW_OPTIONS_KEY]) + } - if (o && typeof o === "object") { - return !!o[TECHNOLOGY_PREVIEW_OPTIONS_KEY]; - } + if (o && typeof o === 'object') { + return !!o[TECHNOLOGY_PREVIEW_OPTIONS_KEY] + } - return false; + return false } -const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE = "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver"; +const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver' /** * A WebDriver client for Safari. This class should never be instantiated @@ -109,34 +109,32 @@ const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE = "/Applications/Safari Technology Pre * */ class Driver extends webdriver.WebDriver { - /** - * Creates a new Safari session. - * - * @param {(Options|Capabilities)=} options The configuration options. - * @return {!Driver} A new driver instance. - */ - static createSession (options) { - let caps = options || new Options(); - - let exe; - if (useTechnologyPreview(caps.get(OPTIONS_CAPABILITY_KEY))) { - exe = SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE; - } - - let service = new ServiceBuilder(exe).build(); - if (!service.getExecutable()) { - service.setExecutable(getBinaryPaths(caps).driverPath); - } - let executor = new http.Executor( - service.start().then((url) => new http.HttpClient(url))); - - return /** @type {!Driver} */ (super.createSession(executor, caps, - () => service.kill())); - } + /** + * Creates a new Safari session. + * + * @param {(Options|Capabilities)=} options The configuration options. + * @return {!Driver} A new driver instance. + */ + static createSession(options) { + let caps = options || new Options() + + let exe + if (useTechnologyPreview(caps.get(OPTIONS_CAPABILITY_KEY))) { + exe = SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE + } + + let service = new ServiceBuilder(exe).build() + if (!service.getExecutable()) { + service.setExecutable(getBinaryPaths(caps).driverPath) + } + let executor = new http.Executor(service.start().then((url) => new http.HttpClient(url))) + + return /** @type {!Driver} */ (super.createSession(executor, caps, () => service.kill())) + } } // Public API -exports.Driver = Driver; -exports.Options = Options; -exports.ServiceBuilder = ServiceBuilder; +exports.Driver = Driver +exports.Options = Options +exports.ServiceBuilder = ServiceBuilder