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