2015-03-17 17:27:20 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2016-01-29 15:57:46 +03:00
|
|
|
const {interfaces: Ci, utils: Cu} = Components;
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2016-07-08 16:00:56 +03:00
|
|
|
const ERRORS = new Set([
|
2017-02-03 22:30:13 +03:00
|
|
|
"ElementClickInterceptedError",
|
2015-04-15 14:18:00 +03:00
|
|
|
"ElementNotAccessibleError",
|
2017-02-03 22:30:13 +03:00
|
|
|
"ElementNotInteractableError",
|
2016-11-06 21:00:18 +03:00
|
|
|
"InsecureCertificateError",
|
2015-04-17 20:43:05 +03:00
|
|
|
"InvalidArgumentError",
|
2017-05-08 19:08:41 +03:00
|
|
|
"InvalidCookieDomainError",
|
2015-03-31 20:00:32 +03:00
|
|
|
"InvalidElementStateError",
|
2015-04-15 14:18:00 +03:00
|
|
|
"InvalidSelectorError",
|
2017-02-10 21:36:52 +03:00
|
|
|
"InvalidSessionIDError",
|
2015-03-17 17:27:20 +03:00
|
|
|
"JavaScriptError",
|
2017-02-17 22:52:58 +03:00
|
|
|
"MoveTargetOutOfBoundsError",
|
2015-03-17 17:27:20 +03:00
|
|
|
"NoAlertOpenError",
|
|
|
|
"NoSuchElementError",
|
|
|
|
"NoSuchFrameError",
|
|
|
|
"NoSuchWindowError",
|
|
|
|
"ScriptTimeoutError",
|
|
|
|
"SessionNotCreatedError",
|
2015-04-15 14:18:00 +03:00
|
|
|
"StaleElementReferenceError",
|
2015-03-17 17:27:20 +03:00
|
|
|
"TimeoutError",
|
2015-04-20 15:53:51 +03:00
|
|
|
"UnableToSetCookieError",
|
2017-04-20 20:00:46 +03:00
|
|
|
"UnexpectedAlertOpenError",
|
2015-03-17 17:27:20 +03:00
|
|
|
"UnknownCommandError",
|
|
|
|
"UnknownError",
|
|
|
|
"UnsupportedOperationError",
|
|
|
|
"WebDriverError",
|
2016-07-08 16:00:56 +03:00
|
|
|
]);
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2016-07-08 15:58:04 +03:00
|
|
|
const BUILTIN_ERRORS = new Set([
|
|
|
|
"Error",
|
|
|
|
"EvalError",
|
|
|
|
"InternalError",
|
|
|
|
"RangeError",
|
|
|
|
"ReferenceError",
|
|
|
|
"SyntaxError",
|
|
|
|
"TypeError",
|
|
|
|
"URIError",
|
|
|
|
]);
|
|
|
|
|
2017-06-30 02:40:24 +03:00
|
|
|
this.EXPORTED_SYMBOLS = ["error", "error.pprint"].concat(Array.from(ERRORS));
|
2015-03-17 17:27:20 +03:00
|
|
|
|
|
|
|
this.error = {};
|
|
|
|
|
|
|
|
/**
|
2017-02-14 19:48:14 +03:00
|
|
|
* Check if |val| is an instance of the |Error| prototype.
|
|
|
|
*
|
|
|
|
* Because error objects may originate from different globals, comparing
|
|
|
|
* the prototype of the left hand side with the prototype property from
|
|
|
|
* the right hand side, which is what |instanceof| does, will not work.
|
|
|
|
* If the LHS and RHS come from different globals, this check will always
|
|
|
|
* fail because the two objects will not have the same identity.
|
|
|
|
*
|
|
|
|
* Therefore it is not safe to use |instanceof| in any multi-global
|
|
|
|
* situation, e.g. in content across multiple Window objects or anywhere
|
|
|
|
* in chrome scope.
|
|
|
|
*
|
|
|
|
* This function also contains a special check if |val| is an XPCOM
|
|
|
|
* |nsIException| because they are special snowflakes and may indeed
|
|
|
|
* cause Firefox to crash if used with |instanceof|.
|
2015-04-15 14:18:00 +03:00
|
|
|
*
|
|
|
|
* @param {*} val
|
|
|
|
* Any value that should be undergo the test for errorness.
|
|
|
|
* @return {boolean}
|
|
|
|
* True if error, false otherwise.
|
2015-03-17 17:27:20 +03:00
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.isError = function(val) {
|
2015-04-15 14:18:00 +03:00
|
|
|
if (val === null || typeof val != "object") {
|
2015-03-17 17:27:20 +03:00
|
|
|
return false;
|
2016-01-07 17:37:06 +03:00
|
|
|
} else if (val instanceof Ci.nsIException) {
|
2015-03-17 17:27:20 +03:00
|
|
|
return true;
|
2017-06-30 02:40:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// DOMRectList errors on string comparison
|
|
|
|
try {
|
|
|
|
let proto = Object.getPrototypeOf(val);
|
|
|
|
return BUILTIN_ERRORS.has(proto.toString());
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
2015-03-17 17:27:20 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if obj is an object in the WebDriverError prototypal chain.
|
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.isWebDriverError = function(obj) {
|
2015-03-17 17:27:20 +03:00
|
|
|
return error.isError(obj) &&
|
2016-07-08 16:00:56 +03:00
|
|
|
("name" in obj && ERRORS.has(obj.name));
|
2016-02-03 21:43:37 +03:00
|
|
|
};
|
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
/**
|
2017-05-08 16:01:30 +03:00
|
|
|
* Ensures error instance is a WebDriverError.
|
|
|
|
*
|
|
|
|
* If the given error is already in the WebDriverError prototype
|
|
|
|
* chain, |err| is returned unmodified. If it is not, it is wrapped
|
|
|
|
* in UnknownError.
|
|
|
|
*
|
|
|
|
* @param {Error} err
|
|
|
|
* Error to conditionally turn into a WebDriverError.
|
|
|
|
*
|
|
|
|
* @return {WebDriverError}
|
|
|
|
* If |err| is a WebDriverError, it is returned unmodified.
|
|
|
|
* Otherwise an UnknownError type is returned.
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.wrap = function(err) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
if (error.isWebDriverError(err)) {
|
|
|
|
return err;
|
|
|
|
}
|
2017-05-08 16:01:30 +03:00
|
|
|
return new UnknownError(err);
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
};
|
|
|
|
|
2015-03-17 17:27:20 +03:00
|
|
|
/**
|
|
|
|
* Unhandled error reporter. Dumps the error and its stacktrace to console,
|
|
|
|
* and reports error to the Browser Console.
|
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.report = function(err) {
|
2017-02-10 21:36:52 +03:00
|
|
|
let msg = "Marionette threw an error: " + error.stringify(err);
|
2015-03-17 17:27:20 +03:00
|
|
|
dump(msg + "\n");
|
|
|
|
if (Cu.reportError) {
|
|
|
|
Cu.reportError(msg);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prettifies an instance of Error and its stacktrace to a string.
|
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.stringify = function(err) {
|
2015-03-17 17:27:20 +03:00
|
|
|
try {
|
|
|
|
let s = err.toString();
|
|
|
|
if ("stack" in err) {
|
|
|
|
s += "\n" + err.stack;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
} catch (e) {
|
|
|
|
return "<unprintable error>";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-11-01 01:00:21 +03:00
|
|
|
/**
|
|
|
|
* Pretty-print values passed to template strings.
|
|
|
|
*
|
|
|
|
* Usage:
|
|
|
|
*
|
2017-06-30 02:40:24 +03:00
|
|
|
* const {pprint} = Cu.import("chrome://marionette/content/error.js", {});
|
2017-02-07 19:59:59 +03:00
|
|
|
* let bool = {value: true};
|
2017-06-30 02:40:24 +03:00
|
|
|
* pprint`Expected boolean, got ${bool}`;
|
2017-02-07 19:59:59 +03:00
|
|
|
* => 'Expected boolean, got [object Object] {"value": true}'
|
|
|
|
*
|
|
|
|
* let htmlElement = document.querySelector("input#foo");
|
2017-06-30 02:40:24 +03:00
|
|
|
* pprint`Expected element ${htmlElement}`;
|
2017-02-07 19:59:59 +03:00
|
|
|
* => 'Expected element <input id="foo" class="bar baz">'
|
2016-11-01 01:00:21 +03:00
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
error.pprint = function(ss, ...values) {
|
|
|
|
function prettyObject(obj) {
|
2017-02-07 19:59:59 +03:00
|
|
|
let proto = Object.prototype.toString.call(obj);
|
|
|
|
let s = "";
|
|
|
|
try {
|
|
|
|
s = JSON.stringify(obj);
|
2017-06-28 21:22:29 +03:00
|
|
|
} catch (e) {
|
|
|
|
if (e instanceof TypeError) {
|
|
|
|
s = `<${e.message}>`;
|
|
|
|
} else {
|
|
|
|
throw e;
|
|
|
|
}
|
2017-02-07 19:59:59 +03:00
|
|
|
}
|
|
|
|
return proto + " " + s;
|
|
|
|
}
|
|
|
|
|
2017-06-30 02:40:24 +03:00
|
|
|
function prettyElement(el) {
|
2017-02-07 19:59:59 +03:00
|
|
|
let ident = [];
|
|
|
|
if (el.id) {
|
|
|
|
ident.push(`id="${el.id}"`);
|
|
|
|
}
|
|
|
|
if (el.classList.length > 0) {
|
|
|
|
ident.push(`class="${el.className}"`);
|
|
|
|
}
|
|
|
|
|
|
|
|
let idents = "";
|
|
|
|
if (ident.length > 0) {
|
|
|
|
idents = " " + ident.join(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
return `<${el.localName}${idents}>`;
|
|
|
|
}
|
|
|
|
|
2016-11-01 01:00:21 +03:00
|
|
|
let res = [];
|
2017-02-07 19:59:59 +03:00
|
|
|
for (let i = 0; i < ss.length; i++) {
|
|
|
|
res.push(ss[i]);
|
2016-11-01 01:00:21 +03:00
|
|
|
if (i < values.length) {
|
|
|
|
let val = values[i];
|
2017-02-07 19:59:59 +03:00
|
|
|
let s;
|
|
|
|
try {
|
|
|
|
if (val && val.nodeType === 1) {
|
|
|
|
s = prettyElement(val);
|
|
|
|
} else {
|
|
|
|
s = prettyObject(val);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
s = typeof val;
|
2016-11-01 01:00:21 +03:00
|
|
|
}
|
2017-02-07 19:59:59 +03:00
|
|
|
res.push(s);
|
2016-11-01 01:00:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return res.join("");
|
|
|
|
};
|
|
|
|
|
2015-09-26 19:12:01 +03:00
|
|
|
/**
|
2017-02-10 21:36:52 +03:00
|
|
|
* WebDriverError is the prototypal parent of all WebDriver errors.
|
|
|
|
* It should not be used directly, as it does not correspond to a real
|
|
|
|
* error in the specification.
|
2015-09-26 19:12:01 +03:00
|
|
|
*/
|
2017-02-10 21:36:52 +03:00
|
|
|
class WebDriverError extends Error {
|
|
|
|
/**
|
|
|
|
* @param {(string|Error)=} x
|
|
|
|
* Optional string describing error situation or Error instance
|
|
|
|
* to propagate.
|
|
|
|
*/
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(x) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(x);
|
|
|
|
this.name = this.constructor.name;
|
|
|
|
this.status = "webdriver error";
|
|
|
|
|
|
|
|
// Error's ctor does not preserve x' stack
|
|
|
|
if (error.isError(x)) {
|
|
|
|
this.stack = x.stack;
|
|
|
|
}
|
2016-01-29 15:57:46 +03:00
|
|
|
}
|
|
|
|
|
2017-06-30 02:40:24 +03:00
|
|
|
toJSON() {
|
2017-02-10 21:36:52 +03:00
|
|
|
return {
|
|
|
|
error: this.status,
|
|
|
|
message: this.message || "",
|
|
|
|
stacktrace: this.stack || "",
|
|
|
|
}
|
2016-01-29 15:57:46 +03:00
|
|
|
}
|
|
|
|
|
2017-06-30 02:40:24 +03:00
|
|
|
static fromJSON(json) {
|
2017-02-10 21:36:52 +03:00
|
|
|
if (typeof json.error == "undefined") {
|
|
|
|
let s = JSON.stringify(json);
|
|
|
|
throw new TypeError("Undeserialisable error type: " + s);
|
|
|
|
}
|
|
|
|
if (!STATUSES.has(json.error)) {
|
|
|
|
throw new TypeError("Not of WebDriverError descent: " + json.error);
|
|
|
|
}
|
2016-01-29 15:57:46 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
let cls = STATUSES.get(json.error);
|
|
|
|
let err = new cls();
|
|
|
|
if ("message" in json) {
|
|
|
|
err.message = json.message;
|
|
|
|
}
|
|
|
|
if ("stacktrace" in json) {
|
|
|
|
err.stack = json.stacktrace;
|
|
|
|
}
|
|
|
|
return err;
|
2016-12-30 14:26:30 +03:00
|
|
|
}
|
2017-02-10 21:36:52 +03:00
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class ElementNotAccessibleError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "element not accessible";
|
|
|
|
}
|
|
|
|
}
|
2015-04-15 14:18:00 +03:00
|
|
|
|
2017-02-03 22:30:13 +03:00
|
|
|
/**
|
|
|
|
* An element click could not be completed because the element receiving
|
|
|
|
* the events is obscuring the element that was requested clicked.
|
|
|
|
*
|
|
|
|
* @param {Element=} obscuredEl
|
|
|
|
* Element obscuring the element receiving the click. Providing this
|
|
|
|
* is not required, but will produce a nicer error message.
|
|
|
|
* @param {Map.<string, number>} coords
|
|
|
|
* Original click location. Providing this is not required, but
|
|
|
|
* will produce a nicer error message.
|
|
|
|
*/
|
|
|
|
class ElementClickInterceptedError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(obscuredEl = undefined, coords = undefined) {
|
2017-02-03 22:30:13 +03:00
|
|
|
let msg = "";
|
|
|
|
if (obscuredEl && coords) {
|
|
|
|
const doc = obscuredEl.ownerDocument;
|
|
|
|
const overlayingEl = doc.elementFromPoint(coords.x, coords.y);
|
2017-04-17 21:34:44 +03:00
|
|
|
|
|
|
|
switch (obscuredEl.style.pointerEvents) {
|
|
|
|
case "none":
|
|
|
|
msg = error.pprint`Element ${obscuredEl} is not clickable ` +
|
|
|
|
`at point (${coords.x},${coords.y}) ` +
|
|
|
|
`because it does not have pointer events enabled, ` +
|
|
|
|
error.pprint`and element ${overlayingEl} ` +
|
|
|
|
`would receive the click instead`;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
msg = error.pprint`Element ${obscuredEl} is not clickable ` +
|
|
|
|
`at point (${coords.x},${coords.y}) ` +
|
|
|
|
error.pprint`because another element ${overlayingEl} ` +
|
|
|
|
`obscures it`;
|
|
|
|
break;
|
|
|
|
}
|
2017-02-03 22:30:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
super(msg);
|
|
|
|
this.status = "element click intercepted";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ElementNotInteractableError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
2017-02-03 22:30:13 +03:00
|
|
|
this.status = "element not interactable";
|
2017-02-10 21:36:52 +03:00
|
|
|
}
|
|
|
|
}
|
2015-03-31 20:00:32 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class InsecureCertificateError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "insecure certificate";
|
|
|
|
}
|
|
|
|
}
|
2016-11-06 21:00:18 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class InvalidArgumentError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "invalid argument";
|
|
|
|
}
|
|
|
|
}
|
2015-04-02 17:16:00 +03:00
|
|
|
|
2017-05-08 19:08:41 +03:00
|
|
|
class InvalidCookieDomainError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-05-08 19:08:41 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "invalid cookie domain";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class InvalidElementStateError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "invalid element state";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class InvalidSelectorError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "invalid selector";
|
|
|
|
}
|
|
|
|
}
|
2015-04-15 14:18:00 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class InvalidSessionIDError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "invalid session id";
|
|
|
|
}
|
|
|
|
}
|
2015-04-15 15:38:01 +03:00
|
|
|
|
2015-03-17 17:27:20 +03:00
|
|
|
/**
|
2017-02-10 21:36:52 +03:00
|
|
|
* Creates a richly annotated error for an error situation that occurred
|
|
|
|
* whilst evaluating injected scripts.
|
2015-03-17 17:27:20 +03:00
|
|
|
*/
|
2017-02-10 21:36:52 +03:00
|
|
|
class JavaScriptError extends WebDriverError {
|
|
|
|
/**
|
|
|
|
* @param {(string|Error)} x
|
|
|
|
* An Error object instance or a string describing the error
|
|
|
|
* situation.
|
|
|
|
* @param {string=} fnName
|
|
|
|
* Name of the function to use in the stack trace message.
|
|
|
|
* @param {string=} file
|
|
|
|
* Filename of the test file on the client.
|
|
|
|
* @param {number=} line
|
|
|
|
* Line number of |file|.
|
|
|
|
* @param {string=} script
|
|
|
|
* Script being executed, in text form.
|
|
|
|
*/
|
2017-06-28 21:24:58 +03:00
|
|
|
constructor(x,
|
|
|
|
{fnName = null, file = null, line = null, script = null} = {}) {
|
2017-02-10 21:36:52 +03:00
|
|
|
let msg = String(x);
|
|
|
|
let trace = "";
|
|
|
|
|
2017-06-28 21:24:58 +03:00
|
|
|
if (fnName !== null) {
|
2017-02-10 21:36:52 +03:00
|
|
|
trace += fnName;
|
2017-06-28 21:24:58 +03:00
|
|
|
if (file !== null) {
|
2017-02-10 21:36:52 +03:00
|
|
|
trace += ` @${file}`;
|
2017-06-28 21:24:58 +03:00
|
|
|
if (line !== null) {
|
2017-02-10 21:36:52 +03:00
|
|
|
trace += `, line ${line}`;
|
|
|
|
}
|
2016-01-18 21:55:52 +03:00
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
}
|
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
if (error.isError(x)) {
|
|
|
|
let jsStack = x.stack.split("\n");
|
|
|
|
let match = jsStack[0].match(/:(\d+):\d+$/);
|
|
|
|
let jsLine = match ? parseInt(match[1]) : 0;
|
2017-06-28 21:24:58 +03:00
|
|
|
if (script !== null) {
|
2017-02-10 21:36:52 +03:00
|
|
|
let src = script.split("\n")[jsLine];
|
|
|
|
trace += "\n" +
|
|
|
|
`inline javascript, line ${jsLine}\n` +
|
|
|
|
`src: "${src}"`;
|
|
|
|
}
|
|
|
|
trace += "\nStack:\n" + x.stack;
|
2015-03-17 17:27:20 +03:00
|
|
|
}
|
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
super(msg);
|
|
|
|
this.status = "javascript error";
|
|
|
|
this.stack = trace;
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-17 22:52:58 +03:00
|
|
|
class MoveTargetOutOfBoundsError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-17 22:52:58 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "move target out of bounds";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class NoAlertOpenError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "no such alert";
|
|
|
|
}
|
|
|
|
}
|
2015-03-31 20:00:32 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class NoSuchElementError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "no such element";
|
|
|
|
}
|
|
|
|
}
|
2015-03-31 20:00:32 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class NoSuchFrameError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "no such frame";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class NoSuchWindowError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "no such window";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class ScriptTimeoutError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "script timeout";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class SessionNotCreatedError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "session not created";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class StaleElementReferenceError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "stale element reference";
|
|
|
|
}
|
|
|
|
}
|
2015-04-15 14:18:00 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class TimeoutError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "timeout";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class UnableToSetCookieError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "unable to set cookie";
|
|
|
|
}
|
|
|
|
}
|
2015-04-20 15:53:51 +03:00
|
|
|
|
2017-04-20 20:00:46 +03:00
|
|
|
class UnexpectedAlertOpenError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-04-20 20:00:46 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "unexpected alert open";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class UnknownCommandError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "unknown command";
|
|
|
|
}
|
|
|
|
}
|
2015-03-31 20:00:32 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class UnknownError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "unknown error";
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 17:27:20 +03:00
|
|
|
|
2017-02-10 21:36:52 +03:00
|
|
|
class UnsupportedOperationError extends WebDriverError {
|
2017-06-30 02:40:24 +03:00
|
|
|
constructor(message) {
|
2017-02-10 21:36:52 +03:00
|
|
|
super(message);
|
|
|
|
this.status = "unsupported operation";
|
|
|
|
}
|
|
|
|
}
|
2016-01-29 15:57:46 +03:00
|
|
|
|
2017-02-10 21:33:37 +03:00
|
|
|
const STATUSES = new Map([
|
2017-04-20 20:00:46 +03:00
|
|
|
["element click intercepted", ElementClickInterceptedError],
|
2017-02-10 21:33:37 +03:00
|
|
|
["element not accessible", ElementNotAccessibleError],
|
2017-02-03 22:30:13 +03:00
|
|
|
["element not interactable", ElementNotInteractableError],
|
2017-02-10 21:33:37 +03:00
|
|
|
["insecure certificate", InsecureCertificateError],
|
|
|
|
["invalid argument", InvalidArgumentError],
|
2017-06-15 15:36:47 +03:00
|
|
|
["invalid cookie domain", InvalidCookieDomainError],
|
2017-02-10 21:33:37 +03:00
|
|
|
["invalid element state", InvalidElementStateError],
|
|
|
|
["invalid selector", InvalidSelectorError],
|
|
|
|
["invalid session id", InvalidSessionIDError],
|
|
|
|
["javascript error", JavaScriptError],
|
2017-02-17 22:52:58 +03:00
|
|
|
["move target out of bounds", MoveTargetOutOfBoundsError],
|
2017-02-10 21:33:37 +03:00
|
|
|
["no alert open", NoAlertOpenError],
|
|
|
|
["no such element", NoSuchElementError],
|
|
|
|
["no such frame", NoSuchFrameError],
|
|
|
|
["no such window", NoSuchWindowError],
|
|
|
|
["script timeout", ScriptTimeoutError],
|
|
|
|
["session not created", SessionNotCreatedError],
|
|
|
|
["stale element reference", StaleElementReferenceError],
|
|
|
|
["timeout", TimeoutError],
|
|
|
|
["unable to set cookie", UnableToSetCookieError],
|
2017-04-20 20:00:46 +03:00
|
|
|
["unexpected alert open", UnexpectedAlertOpenError],
|
2017-02-10 21:33:37 +03:00
|
|
|
["unknown command", UnknownCommandError],
|
|
|
|
["unknown error", UnknownError],
|
|
|
|
["unsupported operation", UnsupportedOperationError],
|
|
|
|
["webdriver error", WebDriverError],
|
|
|
|
]);
|
2017-06-28 21:01:49 +03:00
|
|
|
|
|
|
|
// Errors must be expored on the local this scope so that the
|
|
|
|
// EXPORTED_SYMBOLS and the Cu.import("foo", {}) machinery sees them.
|
|
|
|
// We could assign each error definition directly to |this|, but
|
|
|
|
// because they are Error prototypes this would mess up their names.
|
|
|
|
for (let cls of STATUSES.values()) {
|
|
|
|
this[cls.name] = cls;
|
|
|
|
}
|