Path: blob/trunk/javascript/selenium-webdriver/ie.js
2884 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617/**18* @fileoverview Defines a {@linkplain Driver WebDriver} client for Microsoft's19* Internet Explorer. Before using the IEDriver, you must download the latest20* [IEDriverServer](https://www.selenium.dev/downloads/)21* and place it on your22* [PATH](http://en.wikipedia.org/wiki/PATH_%28variable%29). You must also apply23* the system configuration outlined on the Selenium project24* [wiki](https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver)25*26* @module selenium-webdriver/ie27*/2829'use strict'3031const http = require('./http')32const portprober = require('./net/portprober')33const remote = require('./remote')34const webdriver = require('./lib/webdriver')35const { Browser, Capabilities } = require('./lib/capabilities')36const error = require('./lib/error')37const { getBinaryPaths } = require('./common/driverFinder')3839const OPTIONS_CAPABILITY_KEY = 'se:ieOptions'40const SCROLL_BEHAVIOUR = {41BOTTOM: 1,42TOP: 0,43}4445/**46* IEDriverServer logging levels.47* @enum {string}48*/49const Level = {50FATAL: 'FATAL',51ERROR: 'ERROR',52WARN: 'WARN',53INFO: 'INFO',54DEBUG: 'DEBUG',55TRACE: 'TRACE',56}5758/**59* Option keys:60* https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#ie-specific61* @enum {string}62*/63const Key = {64IGNORE_PROTECTED_MODE_SETTINGS: 'ignoreProtectedModeSettings',65IGNORE_ZOOM_SETTING: 'ignoreZoomSetting',66INITIAL_BROWSER_URL: 'initialBrowserUrl',67ENABLE_PERSISTENT_HOVER: 'enablePersistentHover',68ENABLE_ELEMENT_CACHE_CLEANUP: 'enableElementCacheCleanup',69ELEMENT_SCROLL_BEHAVIOR: 'elementScrollBehavior',70REQUIRE_WINDOW_FOCUS: 'requireWindowFocus',71BROWSER_ATTACH_TIMEOUT: 'browserAttachTimeout',72FORCE_CREATE_PROCESS: 'ie.forceCreateProcessApi',73BROWSER_COMMAND_LINE_SWITCHES: 'ie.browserCommandLineSwitches',74USE_PER_PROCESS_PROXY: 'ie.usePerProcessProxy',75ENSURE_CLEAN_SESSION: 'ie.ensureCleanSession',76LOG_FILE: 'logFile',77LOG_LEVEL: 'logLevel',78HOST: 'host',79EXTRACT_PATH: 'extractPath',80SILENT: 'silent',81FILE_UPLOAD_DIALOG_TIMEOUT: 'ie.fileUploadDialogTimeout',82ATTACH_TO_EDGE_CHROMIUM: 'ie.edgechromium',83EDGE_EXECUTABLE_PATH: 'ie.edgepath',84IGNORE_PROCESS_MATCH: 'ie.ignoreprocessmatch',85}8687/**88* Class for managing IEDriver specific options.89*/90class Options extends Capabilities {91/**92* @param {(Capabilities|Map<string, ?>|Object)=} other Another set of93* capabilities to initialize this instance from.94*/95constructor(other = undefined) {96super(other)9798/** @private {!Object} */99this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {}100101this.set(OPTIONS_CAPABILITY_KEY, this.options_)102this.setBrowserName(Browser.INTERNET_EXPLORER)103}104105/**106* Whether to disable the protected mode settings check when the session is107* created. Disabling this setting may lead to significant instability as the108* browser may become unresponsive/hang. Only "best effort" support is provided109* when using this capability.110*111* For more information, refer to the IEDriver's112* [required system configuration](http://goo.gl/eH0Yi3).113*114* @param {boolean} ignoreSettings Whether to ignore protected mode settings.115* @return {!Options} A self reference.116*/117introduceFlakinessByIgnoringProtectedModeSettings(ignoreSettings) {118this.options_[Key.IGNORE_PROTECTED_MODE_SETTINGS] = !!ignoreSettings119return this120}121122/**123* Indicates whether to skip the check that the browser's zoom level is set to124* 100%.125*126* @param {boolean} ignore Whether to ignore the browser's zoom level settings.127* @return {!Options} A self reference.128*/129ignoreZoomSetting(ignore) {130this.options_[Key.IGNORE_ZOOM_SETTING] = !!ignore131return this132}133134/**135* Sets the initial URL loaded when IE starts. This is intended to be used with136* {@link #introduceFlakinessByIgnoringProtectedModeSettings} to allow the user to initialize IE in137* the proper Protected Mode zone. Setting this option may cause browser138* instability or flaky and unresponsive code. Only "best effort" support is139* provided when using this option.140*141* @param {string} url The initial browser URL.142* @return {!Options} A self reference.143*/144initialBrowserUrl(url) {145this.options_[Key.INITIAL_BROWSER_URL] = url146return this147}148149/**150* Configures whether to enable persistent mouse hovering (true by default).151* Persistent hovering is achieved by continuously firing mouse over events at152* the last location the mouse cursor has been moved to.153*154* @param {boolean} enable Whether to enable persistent hovering.155* @return {!Options} A self reference.156*/157enablePersistentHover(enable) {158this.options_[Key.ENABLE_PERSISTENT_HOVER] = !!enable159return this160}161162/**163* Configures whether the driver should attempt to remove obsolete164* {@linkplain webdriver.WebElement WebElements} from its internal cache on165* page navigation (true by default). Disabling this option will cause the166* driver to run with a larger memory footprint.167*168* @param {boolean} enable Whether to enable element reference cleanup.169* @return {!Options} A self reference.170*/171enableElementCacheCleanup(enable) {172this.options_[Key.ENABLE_ELEMENT_CACHE_CLEANUP] = !!enable173return this174}175176/**177* Configures whether to require the IE window to have input focus before178* performing any user interactions (i.e. mouse or keyboard events). This179* option is disabled by default, but delivers much more accurate interaction180* events when enabled.181*182* @param {boolean} require Whether to require window focus.183* @return {!Options} A self reference.184*/185requireWindowFocus(require) {186this.options_[Key.REQUIRE_WINDOW_FOCUS] = !!require187return this188}189190/**191* Configures the timeout, in milliseconds, that the driver will attempt to192* located and attach to a newly opened instance of Internet Explorer. The193* default is zero, which indicates waiting indefinitely.194*195* @param {number} timeout How long to wait for IE.196* @return {!Options} A self reference.197*/198browserAttachTimeout(timeout) {199this.options_[Key.BROWSER_ATTACH_TIMEOUT] = Math.max(timeout, 0)200return this201}202203/**204* Configures whether to launch Internet Explorer using the CreateProcess API.205* If this option is not specified, IE is launched using IELaunchURL, if206* available. For IE 8 and above, this option requires the TabProcGrowth207* registry value to be set to 0.208*209* @param {boolean} force Whether to use the CreateProcess API.210* @return {!Options} A self reference.211*/212forceCreateProcessApi(force) {213this.options_[Key.FORCE_CREATE_PROCESS] = !!force214return this215}216217/**218* Specifies command-line switches to use when launching Internet Explorer.219* This is only valid when used with {@link #forceCreateProcessApi}.220*221* @param {...(string|!Array.<string>)} args The arguments to add.222* @return {!Options} A self reference.223*/224225addBrowserCommandSwitches(...args) {226let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || []227if (typeof current == 'string') {228current = current.split(' ')229}230this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = current.concat(args).join(' ')231return this232}233234/**235* Specifies command-line switches to use when launching Internet Explorer.236* This is only valid when used with {@link #forceCreateProcessApi}.237*238* @param {...(string|!Array.<string>)} args The arguments to add.239* @deprecated Use {@link #addBrowserCommandSwitches} instead.240* @return {!Options} A self reference.241*/242243addArguments(...args) {244let current = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || []245if (typeof current == 'string') {246current = current.split(' ')247}248this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = current.concat(args).join(' ')249return this250}251252/**253* Configures whether proxies should be configured on a per-process basis. If254* not set, setting a {@linkplain #setProxy proxy} will configure the system255* proxy. The default behavior is to use the system proxy.256*257* @param {boolean} enable Whether to enable per-process proxy settings.258* @return {!Options} A self reference.259*/260usePerProcessProxy(enable) {261this.options_[Key.USE_PER_PROCESS_PROXY] = !!enable262return this263}264265/**266* Configures whether to clear the cache, cookies, history, and saved form data267* before starting the browser. _Using this capability will clear session data268* for all running instances of Internet Explorer, including those started269* manually._270*271* @param {boolean} cleanSession Whether to clear all session data on startup.272* @return {!Options} A self reference.273*/274ensureCleanSession(cleanSession) {275this.options_[Key.ENSURE_CLEAN_SESSION] = !!cleanSession276return this277}278279/**280* Sets the path to the log file the driver should log to.281* @param {string} file The log file path.282* @return {!Options} A self reference.283*/284setLogFile(file) {285this.options_[Key.LOG_FILE] = file286return this287}288289/**290* Sets the IEDriverServer's logging {@linkplain Level level}.291* @param {Level} level The logging level.292* @return {!Options} A self reference.293*/294setLogLevel(level) {295this.options_[Key.LOG_LEVEL] = level296return this297}298299/**300* Sets the IP address of the driver's host adapter.301* @param {string} host The IP address to use.302* @return {!Options} A self reference.303*/304setHost(host) {305this.options_[Key.HOST] = host306return this307}308309/**310* Sets the path of the temporary data directory to use.311* @param {string} path The log file path.312* @return {!Options} A self reference.313*/314setExtractPath(path) {315this.options_[Key.EXTRACT_PATH] = path316return this317}318319/**320* Sets whether the driver should start in silent mode.321* @param {boolean} silent Whether to run in silent mode.322* @return {!Options} A self reference.323*/324silent(silent) {325this.options_[Key.SILENT] = silent326return this327}328329/**330* The options File Upload Dialog Timeout in milliseconds331*332* @param {number} timeout How long to wait for IE.333* @return {!Options} A self reference.334*/335fileUploadDialogTimeout(timeout) {336this.options_[Key.FILE_UPLOAD_DIALOG_TIMEOUT] = Math.max(timeout, 0)337return this338}339340/**341* Sets the path of the EdgeChromium driver.342* @param {string} path The EdgeChromium driver path.343* @return {!Options} A self reference.344*/345setEdgePath(path) {346this.options_[Key.EDGE_EXECUTABLE_PATH] = path347return this348}349350/**351* Sets the IEDriver to drive Chromium-based Edge in Internet Explorer mode.352*353* @param {boolean} attachEdgeChromium Whether to run in Chromium-based-Edge in IE mode354* @return {!Options} A self reference.355*/356setEdgeChromium(attachEdgeChromium) {357this.options_[Key.ATTACH_TO_EDGE_CHROMIUM] = !!attachEdgeChromium358return this359}360361/**362* Sets how elements should be scrolled into view for interaction.363* @param {number} behavior The desired scroll behavior: either 0 to align with364* the top of the viewport or 1 to align with the bottom.365* @return {!Options} A self reference.366*/367setScrollBehavior(behavior) {368if (behavior && behavior !== SCROLL_BEHAVIOUR.TOP && behavior !== SCROLL_BEHAVIOUR.BOTTOM) {369throw new error.InvalidArgumentError(`Element Scroll Behavior out of range.370It should be either ${SCROLL_BEHAVIOUR.TOP} or ${SCROLL_BEHAVIOUR.BOTTOM}`)371}372this.options_[Key.ELEMENT_SCROLL_BEHAVIOR] = behavior373return this374}375}376377function createServiceFromCapabilities(capabilities) {378if (process.platform !== 'win32') {379throw Error(380'The IEDriver may only be used on Windows, but you appear to be on ' +381process.platform +382'. Did you mean to run against a remote ' +383'WebDriver server?',384)385}386387let exe = null // Let Selenium Manager find it388var args = []389if (capabilities.has(Key.HOST)) {390args.push('--host=' + capabilities.get(Key.HOST))391}392if (capabilities.has(Key.LOG_FILE)) {393args.push('--log-file=' + capabilities.get(Key.LOG_FILE))394}395if (capabilities.has(Key.LOG_LEVEL)) {396args.push('--log-level=' + capabilities.get(Key.LOG_LEVEL))397}398if (capabilities.has(Key.EXTRACT_PATH)) {399args.push('--extract-path=' + capabilities.get(Key.EXTRACT_PATH))400}401if (capabilities.get(Key.SILENT)) {402args.push('--silent')403}404405var port = portprober.findFreePort()406return new remote.DriverService(exe, {407loopback: true,408port: port,409args: port.then(function (port) {410return args.concat('--port=' + port)411}),412stdio: 'ignore',413})414}415416/**417* Creates {@link selenium-webdriver/remote.DriverService} instances that manage418* an [IEDriverServer](https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver)419* server in a child process.420*/421class ServiceBuilder extends remote.DriverService.Builder {422/**423* @param {string=} opt_exe Path to the server executable to use. If omitted,424* the builder will attempt to locate the IEDriverServer on the system PATH.425*/426constructor(opt_exe) {427super(opt_exe)428this.setLoopback(true) // Required.429}430}431432/**433* A WebDriver client for Microsoft's Internet Explorer.434*/435class Driver extends webdriver.WebDriver {436/**437* Creates a new session for Microsoft's Internet Explorer.438*439* @param {(Capabilities|Options)=} options The configuration options.440* @param {(remote.DriverService)=} opt_service The `DriverService` to use441* to start the IEDriverServer in a child process, optionally.442* @return {!Driver} A new driver instance.443*/444static createSession(options, opt_service) {445options = options || new Options()446447let service448449if (opt_service instanceof remote.DriverService) {450service = opt_service451} else {452service = createServiceFromCapabilities(options)453}454if (!service.getExecutable()) {455service.setExecutable(getBinaryPaths(options).driverPath)456}457458let client = service.start().then((url) => new http.HttpClient(url))459let executor = new http.Executor(client)460461return /** @type {!Driver} */ (super.createSession(executor, options, () => service.kill()))462}463464/**465* This function is a no-op as file detectors are not supported by this466* implementation.467* @override468*/469setFileDetector() {}470}471472// PUBLIC API473474exports.Driver = Driver475exports.Options = Options476exports.Level = Level477exports.ServiceBuilder = ServiceBuilder478exports.Key = Key479exports.VENDOR_COMMAND_PREFIX = OPTIONS_CAPABILITY_KEY480exports.Behavior = SCROLL_BEHAVIOUR481482483