UNPKG

15.9 kBJavaScriptView Raw
1// Licensed to the Software Freedom Conservancy (SFC) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The SFC licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18'use strict';
19
20/**
21 * The base WebDriver error type. This error type is only used directly when a
22 * more appropriate category is not defined for the offending error.
23 */
24class WebDriverError extends Error {
25 /** @param {string=} opt_error the error message, if any. */
26 constructor(opt_error) {
27 super(opt_error);
28
29 /** @override */
30 this.name = this.constructor.name;
31 }
32}
33
34
35/**
36 * An attempt was made to select an element that cannot be selected.
37 */
38class ElementNotSelectableError extends WebDriverError {
39 /** @param {string=} opt_error the error message, if any. */
40 constructor(opt_error) {
41 super(opt_error);
42 }
43}
44
45
46/**
47 * An element command could not be completed because the element is not visible
48 * on the page.
49 */
50class ElementNotVisibleError extends WebDriverError {
51 /** @param {string=} opt_error the error message, if any. */
52 constructor(opt_error) {
53 super(opt_error);
54 }
55}
56
57
58/**
59 * The arguments passed to a command are either invalid or malformed.
60 */
61class InvalidArgumentError extends WebDriverError {
62 /** @param {string=} opt_error the error message, if any. */
63 constructor(opt_error) {
64 super(opt_error);
65 }
66}
67
68
69/**
70 * An illegal attempt was made to set a cookie under a different domain than
71 * the current page.
72 */
73class InvalidCookieDomainError extends WebDriverError {
74 /** @param {string=} opt_error the error message, if any. */
75 constructor(opt_error) {
76 super(opt_error);
77 }
78}
79
80
81/**
82 * The coordinates provided to an interactions operation are invalid.
83 */
84class InvalidElementCoordinatesError extends WebDriverError {
85 /** @param {string=} opt_error the error message, if any. */
86 constructor(opt_error) {
87 super(opt_error);
88 }
89}
90
91
92/**
93 * An element command could not be completed because the element is in an
94 * invalid state, e.g. attempting to click an element that is no longer attached
95 * to the document.
96 */
97class InvalidElementStateError extends WebDriverError {
98 /** @param {string=} opt_error the error message, if any. */
99 constructor(opt_error) {
100 super(opt_error);
101 }
102}
103
104
105/**
106 * Argument was an invalid selector.
107 */
108class InvalidSelectorError extends WebDriverError {
109 /** @param {string=} opt_error the error message, if any. */
110 constructor(opt_error) {
111 super(opt_error);
112 }
113}
114
115
116/**
117 * Occurs when a command is directed to a session that does not exist.
118 */
119class NoSuchSessionError extends WebDriverError {
120 /** @param {string=} opt_error the error message, if any. */
121 constructor(opt_error) {
122 super(opt_error);
123 }
124}
125
126
127/**
128 * An error occurred while executing JavaScript supplied by the user.
129 */
130class JavascriptError extends WebDriverError {
131 /** @param {string=} opt_error the error message, if any. */
132 constructor(opt_error) {
133 super(opt_error);
134 }
135}
136
137
138/**
139 * The target for mouse interaction is not in the browser’s viewport and cannot
140 * be brought into that viewport.
141 */
142class MoveTargetOutOfBoundsError extends WebDriverError {
143 /** @param {string=} opt_error the error message, if any. */
144 constructor(opt_error) {
145 super(opt_error);
146 }
147}
148
149
150/**
151 * An attempt was made to operate on a modal dialog when one was not open.
152 */
153class NoSuchAlertError extends WebDriverError {
154 /** @param {string=} opt_error the error message, if any. */
155 constructor(opt_error) {
156 super(opt_error);
157 }
158}
159
160
161/**
162 * An element could not be located on the page using the given search
163 * parameters.
164 */
165class NoSuchElementError extends WebDriverError {
166 /** @param {string=} opt_error the error message, if any. */
167 constructor(opt_error) {
168 super(opt_error);
169 }
170}
171
172
173/**
174 * A request to switch to a frame could not be satisfied because the frame
175 * could not be found.
176 */
177class NoSuchFrameError extends WebDriverError {
178 /** @param {string=} opt_error the error message, if any. */
179 constructor(opt_error) {
180 super(opt_error);
181 }
182}
183
184
185/**
186 * A request to switch to a window could not be satisfied because the window
187 * could not be found.
188 */
189class NoSuchWindowError extends WebDriverError {
190 /** @param {string=} opt_error the error message, if any. */
191 constructor(opt_error) {
192 super(opt_error);
193 }
194}
195
196
197/**
198 * A script did not complete before its timeout expired.
199 */
200class ScriptTimeoutError extends WebDriverError {
201 /** @param {string=} opt_error the error message, if any. */
202 constructor(opt_error) {
203 super(opt_error);
204 }
205}
206
207
208/**
209 * A new session could not be created.
210 */
211class SessionNotCreatedError extends WebDriverError {
212 /** @param {string=} opt_error the error message, if any. */
213 constructor(opt_error) {
214 super(opt_error);
215 }
216}
217
218
219
220/**
221 * An element command failed because the referenced element is no longer
222 * attached to the DOM.
223 */
224class StaleElementReferenceError extends WebDriverError {
225 /** @param {string=} opt_error the error message, if any. */
226 constructor(opt_error) {
227 super(opt_error);
228 }
229}
230
231
232/**
233 * An operation did not complete before its timeout expired.
234 */
235class TimeoutError extends WebDriverError {
236 /** @param {string=} opt_error the error message, if any. */
237 constructor(opt_error) {
238 super(opt_error);
239 }
240}
241
242
243/**
244 * A request to set a cookie’s value could not be satisfied.
245 */
246class UnableToSetCookieError extends WebDriverError {
247 /** @param {string=} opt_error the error message, if any. */
248 constructor(opt_error) {
249 super(opt_error);
250 }
251}
252
253
254/**
255 * A screen capture operation was not possible.
256 */
257class UnableToCaptureScreenError extends WebDriverError {
258 /** @param {string=} opt_error the error message, if any. */
259 constructor(opt_error) {
260 super(opt_error);
261 }
262}
263
264
265/**
266 * A modal dialog was open, blocking this operation.
267 */
268class UnexpectedAlertOpenError extends WebDriverError {
269 /**
270 * @param {string=} opt_error the error message, if any.
271 * @param {string=} opt_text the text of the open dialog, if available.
272 */
273 constructor(opt_error, opt_text) {
274 super(opt_error);
275
276 /** @private {(string|undefined)} */
277 this.text_ = opt_text;
278 }
279
280 /**
281 * @return {(string|undefined)} The text displayed with the unhandled alert,
282 * if available.
283 */
284 getAlertText() {
285 return this.text_;
286 }
287}
288
289
290/**
291 * A command could not be executed because the remote end is not aware of it.
292 */
293class UnknownCommandError extends WebDriverError {
294 /** @param {string=} opt_error the error message, if any. */
295 constructor(opt_error) {
296 super(opt_error);
297 }
298}
299
300
301/**
302 * The requested command matched a known URL but did not match an method for
303 * that URL.
304 */
305class UnknownMethodError extends WebDriverError {
306 /** @param {string=} opt_error the error message, if any. */
307 constructor(opt_error) {
308 super(opt_error);
309 }
310}
311
312
313/**
314 * Reports an unsupport operation.
315 */
316class UnsupportedOperationError extends WebDriverError {
317 /** @param {string=} opt_error the error message, if any. */
318 constructor(opt_error) {
319 super(opt_error);
320 }
321}
322
323// TODO(jleyba): Define UnknownError as an alias of WebDriverError?
324
325
326/**
327 * Enum of legacy error codes.
328 * TODO: remove this when all code paths have been switched to the new error
329 * types.
330 * @deprecated
331 * @enum {number}
332 */
333const ErrorCode = {
334 SUCCESS: 0,
335 NO_SUCH_ELEMENT: 7,
336 NO_SUCH_FRAME: 8,
337 UNKNOWN_COMMAND: 9,
338 UNSUPPORTED_OPERATION: 9,
339 STALE_ELEMENT_REFERENCE: 10,
340 ELEMENT_NOT_VISIBLE: 11,
341 INVALID_ELEMENT_STATE: 12,
342 UNKNOWN_ERROR: 13,
343 ELEMENT_NOT_SELECTABLE: 15,
344 JAVASCRIPT_ERROR: 17,
345 XPATH_LOOKUP_ERROR: 19,
346 TIMEOUT: 21,
347 NO_SUCH_WINDOW: 23,
348 INVALID_COOKIE_DOMAIN: 24,
349 UNABLE_TO_SET_COOKIE: 25,
350 UNEXPECTED_ALERT_OPEN: 26,
351 NO_SUCH_ALERT: 27,
352 SCRIPT_TIMEOUT: 28,
353 INVALID_ELEMENT_COORDINATES: 29,
354 IME_NOT_AVAILABLE: 30,
355 IME_ENGINE_ACTIVATION_FAILED: 31,
356 INVALID_SELECTOR_ERROR: 32,
357 SESSION_NOT_CREATED: 33,
358 MOVE_TARGET_OUT_OF_BOUNDS: 34,
359 SQL_DATABASE_ERROR: 35,
360 INVALID_XPATH_SELECTOR: 51,
361 INVALID_XPATH_SELECTOR_RETURN_TYPE: 52,
362 METHOD_NOT_ALLOWED: 405
363};
364
365
366const LEGACY_ERROR_CODE_TO_TYPE = new Map([
367 [ErrorCode.NO_SUCH_ELEMENT, NoSuchElementError],
368 [ErrorCode.NO_SUCH_FRAME, NoSuchFrameError],
369 [ErrorCode.UNSUPPORTED_OPERATION, UnsupportedOperationError],
370 [ErrorCode.STALE_ELEMENT_REFERENCE, StaleElementReferenceError],
371 [ErrorCode.ELEMENT_NOT_VISIBLE, ElementNotVisibleError],
372 [ErrorCode.INVALID_ELEMENT_STATE, InvalidElementStateError],
373 [ErrorCode.UNKNOWN_ERROR, WebDriverError],
374 [ErrorCode.ELEMENT_NOT_SELECTABLE, ElementNotSelectableError],
375 [ErrorCode.JAVASCRIPT_ERROR, JavascriptError],
376 [ErrorCode.XPATH_LOOKUP_ERROR, InvalidSelectorError],
377 [ErrorCode.TIMEOUT, TimeoutError],
378 [ErrorCode.NO_SUCH_WINDOW, NoSuchWindowError],
379 [ErrorCode.INVALID_COOKIE_DOMAIN, InvalidCookieDomainError],
380 [ErrorCode.UNABLE_TO_SET_COOKIE, UnableToSetCookieError],
381 [ErrorCode.UNEXPECTED_ALERT_OPEN, UnexpectedAlertOpenError],
382 [ErrorCode.NO_SUCH_ALERT, NoSuchAlertError],
383 [ErrorCode.SCRIPT_TIMEOUT, ScriptTimeoutError],
384 [ErrorCode.INVALID_ELEMENT_COORDINATES, InvalidElementCoordinatesError],
385 [ErrorCode.INVALID_SELECTOR_ERROR, InvalidSelectorError],
386 [ErrorCode.SESSION_NOT_CREATED, SessionNotCreatedError],
387 [ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS, MoveTargetOutOfBoundsError],
388 [ErrorCode.INVALID_XPATH_SELECTOR, InvalidSelectorError],
389 [ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPE, InvalidSelectorError],
390 [ErrorCode.METHOD_NOT_ALLOWED, UnsupportedOperationError]]);
391
392
393const ERROR_CODE_TO_TYPE = new Map([
394 ['unknown error', WebDriverError],
395 ['element not selectable', ElementNotSelectableError],
396 ['element not visible', ElementNotVisibleError],
397 ['invalid argument', InvalidArgumentError],
398 ['invalid cookie domain', InvalidCookieDomainError],
399 ['invalid element coordinates', InvalidElementCoordinatesError],
400 ['invalid element state', InvalidElementStateError],
401 ['invalid selector', InvalidSelectorError],
402 ['invalid session id', NoSuchSessionError],
403 ['javascript error', JavascriptError],
404 ['move target out of bounds', MoveTargetOutOfBoundsError],
405 ['no such alert', NoSuchAlertError],
406 ['no such element', NoSuchElementError],
407 ['no such frame', NoSuchFrameError],
408 ['no such window', NoSuchWindowError],
409 ['script timeout', ScriptTimeoutError],
410 ['session not created', SessionNotCreatedError],
411 ['stale element reference', StaleElementReferenceError],
412 ['timeout', TimeoutError],
413 ['unable to set cookie', UnableToSetCookieError],
414 ['unable to capture screen', UnableToCaptureScreenError],
415 ['unexpected alert open', UnexpectedAlertOpenError],
416 ['unknown command', UnknownCommandError],
417 ['unknown method', UnknownMethodError],
418 ['unsupported operation', UnsupportedOperationError]]);
419
420
421const TYPE_TO_ERROR_CODE = new Map;
422ERROR_CODE_TO_TYPE.forEach((value, key) => {
423 TYPE_TO_ERROR_CODE.set(value, key);
424});
425
426
427
428/**
429 * @param {*} err The error to encode.
430 * @return {{error: string, message: string}} the encoded error.
431 */
432function encodeError(err) {
433 let type = WebDriverError;
434 if (err instanceof WebDriverError
435 && TYPE_TO_ERROR_CODE.has(err.constructor)) {
436 type = err.constructor;
437 }
438
439 let message = err instanceof Error
440 ? err.message
441 : err + '';
442
443 let code = /** @type {string} */(TYPE_TO_ERROR_CODE.get(type));
444 return {'error': code, 'message': message};
445}
446
447
448/**
449 * Checks a response object from a server that adheres to the W3C WebDriver
450 * protocol.
451 * @param {*} data The response data to check.
452 * @return {*} The response data if it was not an encoded error.
453 * @throws {WebDriverError} the decoded error, if present in the data object.
454 * @deprecated Use {@link #throwDecodedError(data)} instead.
455 * @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol
456 */
457function checkResponse(data) {
458 if (data && typeof data.error === 'string') {
459 let ctor = ERROR_CODE_TO_TYPE.get(data.error) || WebDriverError;
460 throw new ctor(data.message);
461 }
462 return data;
463}
464
465
466/**
467 * Throws an error coded from the W3C protocol. A generic error will be thrown
468 * if the privded `data` is not a valid encoded error.
469 *
470 * @param {{error: string, message: string}} data The error data to decode.
471 * @throws {WebDriverError} the decoded error.
472 * @see https://w3c.github.io/webdriver/webdriver-spec.html#protocol
473 */
474function throwDecodedError(data) {
475 if (data && typeof data === 'object' && typeof data.error === 'string') {
476 let ctor = ERROR_CODE_TO_TYPE.get(data.error) || WebDriverError;
477 throw new ctor(data.message);
478 }
479 throw new WebDriverError('Unknown error: ' + JSON.stringify(data));
480}
481
482
483/**
484 * Checks a legacy response from the Selenium 2.0 wire protocol for an error.
485 * @param {*} responseObj the response object to check.
486 * @return {*} responseObj the original response if it does not define an error.
487 * @throws {WebDriverError} if the response object defines an error.
488 */
489function checkLegacyResponse(responseObj) {
490 // Handle the legacy Selenium error response format.
491 if (responseObj
492 && typeof responseObj === 'object'
493 && typeof responseObj['status'] === 'number'
494 && responseObj['status'] !== 0) {
495 let status = responseObj['status'];
496 let ctor = LEGACY_ERROR_CODE_TO_TYPE.get(status) || WebDriverError;
497
498 let value = responseObj['value'];
499
500 if (!value || typeof value !== 'object') {
501 throw new ctor(value + '');
502 } else {
503 let message = value['message'] + '';
504 if (ctor !== UnexpectedAlertOpenError) {
505 throw new ctor(message);
506 }
507
508 let text = '';
509 if (value['alert'] && typeof value['alert']['text'] === 'string') {
510 text = value['alert']['text'];
511 }
512 throw new UnexpectedAlertOpenError(message, text);
513 }
514 }
515 return responseObj;
516}
517
518
519// PUBLIC API
520
521
522module.exports = {
523 ErrorCode: ErrorCode,
524
525 WebDriverError: WebDriverError,
526 ElementNotSelectableError: ElementNotSelectableError,
527 ElementNotVisibleError: ElementNotVisibleError,
528 InvalidArgumentError: InvalidArgumentError,
529 InvalidCookieDomainError: InvalidCookieDomainError,
530 InvalidElementCoordinatesError: InvalidElementCoordinatesError,
531 InvalidElementStateError: InvalidElementStateError,
532 InvalidSelectorError: InvalidSelectorError,
533 JavascriptError: JavascriptError,
534 MoveTargetOutOfBoundsError: MoveTargetOutOfBoundsError,
535 NoSuchAlertError: NoSuchAlertError,
536 NoSuchElementError: NoSuchElementError,
537 NoSuchFrameError: NoSuchFrameError,
538 NoSuchSessionError: NoSuchSessionError,
539 NoSuchWindowError: NoSuchWindowError,
540 ScriptTimeoutError: ScriptTimeoutError,
541 SessionNotCreatedError: SessionNotCreatedError,
542 StaleElementReferenceError: StaleElementReferenceError,
543 TimeoutError: TimeoutError,
544 UnableToSetCookieError: UnableToSetCookieError,
545 UnableToCaptureScreenError: UnableToCaptureScreenError,
546 UnexpectedAlertOpenError: UnexpectedAlertOpenError,
547 UnknownCommandError: UnknownCommandError,
548 UnknownMethodError: UnknownMethodError,
549 UnsupportedOperationError: UnsupportedOperationError,
550
551 checkResponse: checkResponse,
552 checkLegacyResponse: checkLegacyResponse,
553 encodeError: encodeError,
554 throwDecodedError: throwDecodedError,
555};