Path: blob/trunk/javascript/selenium-webdriver/lib/error.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'use strict'1819const { isObject } = require('./util')2021/**22* The base WebDriver error type. This error type is only used directly when a23* more appropriate category is not defined for the offending error.24*/25class WebDriverError extends Error {26/** @param {string=} opt_error the error message, if any. */27constructor(opt_error) {28super(opt_error)2930/** @override */31this.name = this.constructor.name3233/**34* A stacktrace reported by the remote webdriver endpoint that initially35* reported this error. This property will be an empty string if the remote36* end did not provide a stacktrace.37* @type {string}38*/39this.remoteStacktrace = ''40}41}4243/**44* Indicates the shadow root is no longer attached to the DOM45*/46class DetachedShadowRootError extends WebDriverError {47/** @param {string=} opt_error the error message, if any. */48constructor(opt_error) {49super(opt_error)50}51}5253/**54* Indicates a {@linkplain ./webdriver.WebElement#click click command} could not55* completed because the click target is obscured by other elements on the56* page.57*/58class ElementClickInterceptedError extends WebDriverError {59/** @param {string=} opt_error the error message, if any. */60constructor(opt_error) {61super(opt_error)62}63}6465/**66* An attempt was made to select an element that cannot be selected.67*/68class ElementNotSelectableError extends WebDriverError {69/** @param {string=} opt_error the error message, if any. */70constructor(opt_error) {71super(opt_error)72}73}7475/**76* Indicates a command could not be completed because the target element is77* not pointer or keyboard interactable. This will often occur if an element78* is present in the DOM, but not rendered (i.e. its CSS style has79* "display: none").80*/81class ElementNotInteractableError extends WebDriverError {82/** @param {string=} opt_error the error message, if any. */83constructor(opt_error) {84super(opt_error)85}86}8788/**89* Indicates a navigation event caused the browser to generate a certificate90* warning. This is usually caused by an expired or invalid TLS certificate.91*/92class InsecureCertificateError extends WebDriverError {93/** @param {string=} opt_error the error message, if any. */94constructor(opt_error) {95super(opt_error)96}97}9899/**100* The arguments passed to a command are either invalid or malformed.101*/102class InvalidArgumentError extends WebDriverError {103/** @param {string=} opt_error the error message, if any. */104constructor(opt_error) {105super(opt_error)106}107}108109/**110* An illegal attempt was made to set a cookie under a different domain than111* the current page.112*/113class InvalidCookieDomainError extends WebDriverError {114/** @param {string=} opt_error the error message, if any. */115constructor(opt_error) {116super(opt_error)117}118}119120/**121* The coordinates provided to an interactions operation are invalid.122*/123class InvalidCoordinatesError extends WebDriverError {124/** @param {string=} opt_error the error message, if any. */125constructor(opt_error) {126super(opt_error)127}128}129130/**131* An element command could not be completed because the element is in an132* invalid state, e.g. attempting to click an element that is no longer attached133* to the document.134*/135class InvalidElementStateError extends WebDriverError {136/** @param {string=} opt_error the error message, if any. */137constructor(opt_error) {138super(opt_error)139}140}141142/**143* Argument was an invalid selector.144*/145class InvalidSelectorError extends WebDriverError {146/** @param {string=} opt_error the error message, if any. */147constructor(opt_error) {148super(opt_error)149}150}151152/**153* Occurs when a command is directed to a session that does not exist.154*/155class NoSuchSessionError extends WebDriverError {156/** @param {string=} opt_error the error message, if any. */157constructor(opt_error) {158super(opt_error)159}160}161162/**163* An error occurred while executing JavaScript supplied by the user.164*/165class JavascriptError extends WebDriverError {166/** @param {string=} opt_error the error message, if any. */167constructor(opt_error) {168super(opt_error)169}170}171172/**173* The target for mouse interaction is not in the browser’s viewport and cannot174* be brought into that viewport.175*/176class MoveTargetOutOfBoundsError extends WebDriverError {177/** @param {string=} opt_error the error message, if any. */178constructor(opt_error) {179super(opt_error)180}181}182183/**184* An attempt was made to operate on a modal dialog when one was not open.185*/186class NoSuchAlertError extends WebDriverError {187/** @param {string=} opt_error the error message, if any. */188constructor(opt_error) {189super(opt_error)190}191}192193/**194* Indicates a named cookie could not be found in the cookie jar for the195* currently selected document.196*/197class NoSuchCookieError extends WebDriverError {198/** @param {string=} opt_error the error message, if any. */199constructor(opt_error) {200super(opt_error)201}202}203204/**205* An element could not be located on the page using the given search206* parameters.207*/208class NoSuchElementError extends WebDriverError {209/** @param {string=} opt_error the error message, if any. */210constructor(opt_error) {211super(opt_error)212}213}214215/**216* A ShadowRoot could not be located on the element217*/218class NoSuchShadowRootError extends WebDriverError {219/** @param {string=} opt_error the error message, if any. */220constructor(opt_error) {221super(opt_error)222}223}224225/**226* A request to switch to a frame could not be satisfied because the frame227* could not be found.228*/229class NoSuchFrameError extends WebDriverError {230/** @param {string=} opt_error the error message, if any. */231constructor(opt_error) {232super(opt_error)233}234}235236/**237* A request to switch to a window could not be satisfied because the window238* could not be found.239*/240class NoSuchWindowError extends WebDriverError {241/** @param {string=} opt_error the error message, if any. */242constructor(opt_error) {243super(opt_error)244}245}246247/**248* A script did not complete before its timeout expired.249*/250class ScriptTimeoutError extends WebDriverError {251/** @param {string=} opt_error the error message, if any. */252constructor(opt_error) {253super(opt_error)254}255}256257/**258* A new session could not be created.259*/260class SessionNotCreatedError extends WebDriverError {261/** @param {string=} opt_error the error message, if any. */262constructor(opt_error) {263super(opt_error)264}265}266267/**268* An element command failed because the referenced element is no longer269* attached to the DOM.270*/271class StaleElementReferenceError extends WebDriverError {272/** @param {string=} opt_error the error message, if any. */273constructor(opt_error) {274super(opt_error)275}276}277278/**279* An operation did not complete before its timeout expired.280*/281class TimeoutError extends WebDriverError {282/** @param {string=} opt_error the error message, if any. */283constructor(opt_error) {284super(opt_error)285}286}287288/**289* A request to set a cookie’s value could not be satisfied.290*/291class UnableToSetCookieError extends WebDriverError {292/** @param {string=} opt_error the error message, if any. */293constructor(opt_error) {294super(opt_error)295}296}297298/**299* A screen capture operation was not possible.300*/301class UnableToCaptureScreenError extends WebDriverError {302/** @param {string=} opt_error the error message, if any. */303constructor(opt_error) {304super(opt_error)305}306}307308/**309* A modal dialog was open, blocking this operation.310*/311class UnexpectedAlertOpenError extends WebDriverError {312/**313* @param {string=} opt_error the error message, if any.314* @param {string=} opt_text the text of the open dialog, if available.315*/316constructor(opt_error, opt_text) {317super(opt_error)318319/** @private {(string|undefined)} */320this.text_ = opt_text321}322323/**324* @return {(string|undefined)} The text displayed with the unhandled alert,325* if available.326*/327getAlertText() {328return this.text_329}330}331332/**333* A command could not be executed because the remote end is not aware of it.334*/335class UnknownCommandError extends WebDriverError {336/** @param {string=} opt_error the error message, if any. */337constructor(opt_error) {338super(opt_error)339}340}341342/**343* The requested command matched a known URL but did not match an method for344* that URL.345*/346class UnknownMethodError extends WebDriverError {347/** @param {string=} opt_error the error message, if any. */348constructor(opt_error) {349super(opt_error)350}351}352353/**354* Reports an unsupported operation.355*/356class UnsupportedOperationError extends WebDriverError {357/** @param {string=} opt_error the error message, if any. */358constructor(opt_error) {359super(opt_error)360}361}362363// TODO(jleyba): Define UnknownError as an alias of WebDriverError?364365/**366* Enum of legacy error codes.367* TODO: remove this when all code paths have been switched to the new error368* types.369* @deprecated370* @enum {number}371*/372const ErrorCode = {373SUCCESS: 0,374NO_SUCH_SESSION: 6,375NO_SUCH_ELEMENT: 7,376NO_SUCH_FRAME: 8,377UNKNOWN_COMMAND: 9,378UNSUPPORTED_OPERATION: 9,379STALE_ELEMENT_REFERENCE: 10,380ELEMENT_NOT_VISIBLE: 11,381INVALID_ELEMENT_STATE: 12,382UNKNOWN_ERROR: 13,383ELEMENT_NOT_SELECTABLE: 15,384JAVASCRIPT_ERROR: 17,385XPATH_LOOKUP_ERROR: 19,386TIMEOUT: 21,387NO_SUCH_WINDOW: 23,388INVALID_COOKIE_DOMAIN: 24,389UNABLE_TO_SET_COOKIE: 25,390UNEXPECTED_ALERT_OPEN: 26,391NO_SUCH_ALERT: 27,392SCRIPT_TIMEOUT: 28,393INVALID_ELEMENT_COORDINATES: 29,394IME_NOT_AVAILABLE: 30,395IME_ENGINE_ACTIVATION_FAILED: 31,396INVALID_SELECTOR_ERROR: 32,397SESSION_NOT_CREATED: 33,398MOVE_TARGET_OUT_OF_BOUNDS: 34,399SQL_DATABASE_ERROR: 35,400INVALID_XPATH_SELECTOR: 51,401INVALID_XPATH_SELECTOR_RETURN_TYPE: 52,402ELEMENT_NOT_INTERACTABLE: 60,403INVALID_ARGUMENT: 61,404NO_SUCH_COOKIE: 62,405UNABLE_TO_CAPTURE_SCREEN: 63,406ELEMENT_CLICK_INTERCEPTED: 64,407DETACHED_SHADOW_ROOT: 65,408METHOD_NOT_ALLOWED: 405,409}410411const LEGACY_ERROR_CODE_TO_TYPE = new Map([412[ErrorCode.NO_SUCH_SESSION, NoSuchSessionError],413[ErrorCode.NO_SUCH_ELEMENT, NoSuchElementError],414[ErrorCode.NO_SUCH_FRAME, NoSuchFrameError],415[ErrorCode.UNSUPPORTED_OPERATION, UnsupportedOperationError],416[ErrorCode.STALE_ELEMENT_REFERENCE, StaleElementReferenceError],417[ErrorCode.INVALID_ELEMENT_STATE, InvalidElementStateError],418[ErrorCode.UNKNOWN_ERROR, WebDriverError],419[ErrorCode.ELEMENT_NOT_SELECTABLE, ElementNotSelectableError],420[ErrorCode.JAVASCRIPT_ERROR, JavascriptError],421[ErrorCode.XPATH_LOOKUP_ERROR, InvalidSelectorError],422[ErrorCode.TIMEOUT, TimeoutError],423[ErrorCode.NO_SUCH_WINDOW, NoSuchWindowError],424[ErrorCode.INVALID_COOKIE_DOMAIN, InvalidCookieDomainError],425[ErrorCode.UNABLE_TO_SET_COOKIE, UnableToSetCookieError],426[ErrorCode.UNEXPECTED_ALERT_OPEN, UnexpectedAlertOpenError],427[ErrorCode.NO_SUCH_ALERT, NoSuchAlertError],428[ErrorCode.SCRIPT_TIMEOUT, ScriptTimeoutError],429[ErrorCode.INVALID_ELEMENT_COORDINATES, InvalidCoordinatesError],430[ErrorCode.INVALID_SELECTOR_ERROR, InvalidSelectorError],431[ErrorCode.SESSION_NOT_CREATED, SessionNotCreatedError],432[ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS, MoveTargetOutOfBoundsError],433[ErrorCode.INVALID_XPATH_SELECTOR, InvalidSelectorError],434[ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPE, InvalidSelectorError],435[ErrorCode.ELEMENT_NOT_INTERACTABLE, ElementNotInteractableError],436[ErrorCode.INVALID_ARGUMENT, InvalidArgumentError],437[ErrorCode.NO_SUCH_COOKIE, NoSuchCookieError],438[ErrorCode.UNABLE_TO_CAPTURE_SCREEN, UnableToCaptureScreenError],439[ErrorCode.ELEMENT_CLICK_INTERCEPTED, ElementClickInterceptedError],440[ErrorCode.DETACHED_SHADOW_ROOT, DetachedShadowRootError],441[ErrorCode.METHOD_NOT_ALLOWED, UnsupportedOperationError],442])443444const ERROR_CODE_TO_TYPE = new Map([445['unknown error', WebDriverError],446['detached shadow root', DetachedShadowRootError],447['element click intercepted', ElementClickInterceptedError],448['element not interactable', ElementNotInteractableError],449['element not selectable', ElementNotSelectableError],450['insecure certificate', InsecureCertificateError],451['invalid argument', InvalidArgumentError],452['invalid cookie domain', InvalidCookieDomainError],453['invalid coordinates', InvalidCoordinatesError],454['invalid element state', InvalidElementStateError],455['invalid selector', InvalidSelectorError],456['invalid session id', NoSuchSessionError],457['javascript error', JavascriptError],458['move target out of bounds', MoveTargetOutOfBoundsError],459['no such alert', NoSuchAlertError],460['no such cookie', NoSuchCookieError],461['no such element', NoSuchElementError],462['no such frame', NoSuchFrameError],463['no such shadow root', NoSuchShadowRootError],464['no such window', NoSuchWindowError],465['script timeout', ScriptTimeoutError],466['session not created', SessionNotCreatedError],467['stale element reference', StaleElementReferenceError],468['timeout', TimeoutError],469['unable to set cookie', UnableToSetCookieError],470['unable to capture screen', UnableToCaptureScreenError],471['unexpected alert open', UnexpectedAlertOpenError],472['unknown command', UnknownCommandError],473['unknown method', UnknownMethodError],474['unsupported operation', UnsupportedOperationError],475])476477const TYPE_TO_ERROR_CODE = new Map()478ERROR_CODE_TO_TYPE.forEach((value, key) => {479TYPE_TO_ERROR_CODE.set(value, key)480})481482/**483* @param {*} err The error to encode.484* @return {{error: string, message: string}} the encoded error.485*/486function encodeError(err) {487let type = WebDriverError488if (err instanceof WebDriverError && TYPE_TO_ERROR_CODE.has(err.constructor)) {489type = err.constructor490}491492let message = err instanceof Error ? err.message : err + ''493494let code = /** @type {string} */ (TYPE_TO_ERROR_CODE.get(type))495return { error: code, message: message }496}497498/**499* Tests if the given value is a valid error response object according to the500* W3C WebDriver spec.501*502* @param {?} data The value to test.503* @return {boolean} Whether the given value data object is a valid error504* response.505* @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol506*/507function isErrorResponse(data) {508return isObject(data) && typeof data.error === 'string'509}510511/**512* Throws an error coded from the W3C protocol. A generic error will be thrown513* if the provided `data` is not a valid encoded error.514*515* @param {{error: string, message: string}} data The error data to decode.516* @throws {WebDriverError} the decoded error.517* @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol518*/519function throwDecodedError(data) {520if (isErrorResponse(data)) {521let ctor = ERROR_CODE_TO_TYPE.get(data.error) || WebDriverError522let err = new ctor(data.message)523// TODO(jleyba): remove whichever case is excluded from the final W3C spec.524if (typeof data.stacktrace === 'string') {525err.remoteStacktrace = data.stacktrace526} else if (typeof data.stackTrace === 'string') {527err.remoteStacktrace = data.stackTrace528}529throw err530}531throw new WebDriverError('Unknown error: ' + JSON.stringify(data))532}533534/**535* Checks a legacy response from the Selenium 2.0 wire protocol for an error.536* @param {*} responseObj the response object to check.537* @return {*} responseObj the original response if it does not define an error.538* @throws {WebDriverError} if the response object defines an error.539*/540function checkLegacyResponse(responseObj) {541// Handle the legacy Selenium error response format.542if (isObject(responseObj) && typeof responseObj.status === 'number' && responseObj.status !== 0) {543const { status, value } = responseObj544545let ctor = LEGACY_ERROR_CODE_TO_TYPE.get(status) || WebDriverError546547if (!value || typeof value !== 'object') {548throw new ctor(value + '')549} else {550let message = value['message'] + ''551if (ctor !== UnexpectedAlertOpenError) {552throw new ctor(message)553}554555let text = ''556if (value['alert'] && typeof value['alert']['text'] === 'string') {557text = value['alert']['text']558}559throw new UnexpectedAlertOpenError(message, text)560}561}562return responseObj563}564565// PUBLIC API566567module.exports = {568ErrorCode,569570WebDriverError,571DetachedShadowRootError,572ElementClickInterceptedError,573ElementNotInteractableError,574ElementNotSelectableError,575InsecureCertificateError,576InvalidArgumentError,577InvalidCookieDomainError,578InvalidCoordinatesError,579InvalidElementStateError,580InvalidSelectorError,581JavascriptError,582MoveTargetOutOfBoundsError,583NoSuchAlertError,584NoSuchCookieError,585NoSuchElementError,586NoSuchFrameError,587NoSuchShadowRootError,588NoSuchSessionError,589NoSuchWindowError,590ScriptTimeoutError,591SessionNotCreatedError,592StaleElementReferenceError,593TimeoutError,594UnableToSetCookieError,595UnableToCaptureScreenError,596UnexpectedAlertOpenError,597UnknownCommandError,598UnknownMethodError,599UnsupportedOperationError,600checkLegacyResponse,601encodeError,602isErrorResponse,603throwDecodedError,604}605606607