2015-03-17 07:27:20 -07: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";
|
|
|
|
|
2015-04-15 04:18:00 -07:00
|
|
|
const {results: Cr, utils: Cu} = Components;
|
2015-03-17 07:27:20 -07:00
|
|
|
|
|
|
|
const errors = [
|
2015-04-15 04:18:00 -07:00
|
|
|
"ElementNotAccessibleError",
|
2015-03-17 07:27:20 -07:00
|
|
|
"ElementNotVisibleError",
|
|
|
|
"FrameSendFailureError",
|
|
|
|
"FrameSendNotInitializedError",
|
2015-04-02 07:16:00 -07:00
|
|
|
"IllegalArgumentError",
|
2015-03-31 10:00:32 -07:00
|
|
|
"InvalidElementStateError",
|
2015-04-15 04:18:00 -07:00
|
|
|
"InvalidSelectorError",
|
2015-04-15 05:38:01 -07:00
|
|
|
"InvalidSessionIdError",
|
2015-03-17 07:27:20 -07:00
|
|
|
"JavaScriptError",
|
|
|
|
"NoAlertOpenError",
|
|
|
|
"NoSuchElementError",
|
|
|
|
"NoSuchFrameError",
|
|
|
|
"NoSuchWindowError",
|
|
|
|
"ScriptTimeoutError",
|
|
|
|
"SessionNotCreatedError",
|
2015-04-15 04:18:00 -07:00
|
|
|
"StaleElementReferenceError",
|
2015-03-17 07:27:20 -07:00
|
|
|
"TimeoutError",
|
2015-04-20 05:53:51 -07:00
|
|
|
"UnableToSetCookieError",
|
2015-03-17 07:27:20 -07:00
|
|
|
"UnknownCommandError",
|
|
|
|
"UnknownError",
|
|
|
|
"UnsupportedOperationError",
|
|
|
|
"WebDriverError",
|
|
|
|
];
|
|
|
|
|
|
|
|
this.EXPORTED_SYMBOLS = ["error"].concat(errors);
|
|
|
|
|
2015-04-15 04:18:00 -07:00
|
|
|
// Because XPCOM is a cesspool of undocumented odd behaviour,
|
|
|
|
// Object.getPrototypeOf(err) causes another exception if err is an XPCOM
|
|
|
|
// exception, and cannot be used to determine if err is a prototypal Error.
|
|
|
|
//
|
|
|
|
// Consequently we need to check for properties in its prototypal chain
|
|
|
|
// (using in, instead of err.hasOwnProperty because that causes other
|
|
|
|
// issues).
|
|
|
|
//
|
|
|
|
// Since the input is arbitrary it might _not_ be an Error, and can as
|
|
|
|
// such be an object with a "result" property without it being considered to
|
|
|
|
// be an exception. The solution is to build a lookup table of XPCOM
|
|
|
|
// exceptions from Components.results and check if the value of err#results
|
|
|
|
// is in that table.
|
|
|
|
const XPCOM_EXCEPTIONS = [];
|
|
|
|
{
|
|
|
|
for (let prop in Cr) {
|
|
|
|
XPCOM_EXCEPTIONS.push(Cr[prop]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-17 07:27:20 -07:00
|
|
|
this.error = {};
|
|
|
|
|
|
|
|
error.toJSON = function(err) {
|
|
|
|
return {
|
|
|
|
message: err.message,
|
|
|
|
stacktrace: err.stack || null,
|
2015-04-08 11:02:34 -07:00
|
|
|
status: err.status
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2015-04-08 11:02:34 -07:00
|
|
|
* Determines if the given status is successful.
|
2015-03-17 07:27:20 -07:00
|
|
|
*/
|
2015-04-08 11:02:34 -07:00
|
|
|
error.isSuccess = status => status === "success";
|
2015-03-17 07:27:20 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if obj is an instance of the Error prototype in a safe manner.
|
|
|
|
* Prefer using this over using instanceof since the Error prototype
|
|
|
|
* isn't unique across browsers, and XPCOM exceptions are special
|
|
|
|
* snowflakes.
|
2015-04-15 04:18:00 -07:00
|
|
|
*
|
|
|
|
* @param {*} val
|
|
|
|
* Any value that should be undergo the test for errorness.
|
|
|
|
* @return {boolean}
|
|
|
|
* True if error, false otherwise.
|
2015-03-17 07:27:20 -07:00
|
|
|
*/
|
2015-04-15 04:18:00 -07:00
|
|
|
error.isError = function(val) {
|
|
|
|
if (val === null || typeof val != "object") {
|
2015-03-17 07:27:20 -07:00
|
|
|
return false;
|
2015-04-15 04:18:00 -07:00
|
|
|
} else if ("result" in val && val.result in XPCOM_EXCEPTIONS) {
|
2015-03-17 07:27:20 -07:00
|
|
|
return true;
|
|
|
|
} else {
|
2015-04-08 11:02:34 -07:00
|
|
|
return Object.getPrototypeOf(val) == "Error";
|
2015-03-17 07:27:20 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if obj is an object in the WebDriverError prototypal chain.
|
|
|
|
*/
|
|
|
|
error.isWebDriverError = function(obj) {
|
|
|
|
return error.isError(obj) &&
|
2015-04-08 11:02:34 -07:00
|
|
|
("name" in obj && errors.indexOf(obj.name) > 0);
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unhandled error reporter. Dumps the error and its stacktrace to console,
|
|
|
|
* and reports error to the Browser Console.
|
|
|
|
*/
|
|
|
|
error.report = function(err) {
|
|
|
|
let msg = `Marionette threw an error: ${error.stringify(err)}`;
|
|
|
|
dump(msg + "\n");
|
|
|
|
if (Cu.reportError) {
|
|
|
|
Cu.reportError(msg);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prettifies an instance of Error and its stacktrace to a string.
|
|
|
|
*/
|
|
|
|
error.stringify = function(err) {
|
|
|
|
try {
|
|
|
|
let s = err.toString();
|
|
|
|
if ("stack" in err) {
|
|
|
|
s += "\n" + err.stack;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
} catch (e) {
|
|
|
|
return "<unprintable error>";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
this.WebDriverError = function(msg) {
|
|
|
|
Error.call(this, msg);
|
|
|
|
this.name = "WebDriverError";
|
|
|
|
this.message = msg;
|
2015-04-02 12:07:20 -07:00
|
|
|
this.status = "webdriver error";
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
|
|
|
WebDriverError.prototype = Object.create(Error.prototype);
|
|
|
|
|
2015-04-15 04:18:00 -07:00
|
|
|
this.ElementNotAccessibleError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "ElementNotAccessibleError";
|
|
|
|
this.status = "element not accessible";
|
|
|
|
};
|
|
|
|
ElementNotAccessibleError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-17 07:27:20 -07:00
|
|
|
this.ElementNotVisibleError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "ElementNotVisibleError";
|
|
|
|
this.status = "element not visible";
|
|
|
|
};
|
|
|
|
ElementNotVisibleError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.FrameSendFailureError = function(frame) {
|
|
|
|
this.message = "Error sending message to frame (NS_ERROR_FAILURE)";
|
|
|
|
WebDriverError.call(this, this.message);
|
|
|
|
this.name = "FrameSendFailureError";
|
|
|
|
this.status = "frame send failure error";
|
|
|
|
this.frame = frame;
|
|
|
|
this.errMsg = `${this.message} ${this.frame}; frame not responding.`;
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
2015-03-31 10:00:32 -07:00
|
|
|
FrameSendFailureError.prototype = Object.create(WebDriverError.prototype);
|
2015-03-17 07:27:20 -07:00
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.FrameSendNotInitializedError = function(frame) {
|
|
|
|
this.message = "Error sending message to frame (NS_ERROR_NOT_INITIALIZED)";
|
|
|
|
WebDriverError.call(this, this.message);
|
|
|
|
this.name = "FrameSendNotInitializedError";
|
|
|
|
this.status = "frame send not initialized error";
|
|
|
|
this.frame = frame;
|
|
|
|
this.errMsg = `${this.message} ${this.frame}; frame has closed.`;
|
|
|
|
};
|
|
|
|
FrameSendNotInitializedError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-04-02 07:16:00 -07:00
|
|
|
this.IllegalArgumentError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "IllegalArgumentError";
|
|
|
|
this.status = "illegal argument";
|
|
|
|
};
|
|
|
|
IllegalArgumentError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.InvalidElementStateError = function(msg) {
|
2015-03-17 07:27:20 -07:00
|
|
|
WebDriverError.call(this, msg);
|
2015-03-31 10:00:32 -07:00
|
|
|
this.name = "InvalidElementStateError";
|
|
|
|
this.status = "invalid element state";
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
2015-03-31 10:00:32 -07:00
|
|
|
InvalidElementStateError.prototype = Object.create(WebDriverError.prototype);
|
2015-03-17 07:27:20 -07:00
|
|
|
|
2015-04-15 04:18:00 -07:00
|
|
|
this.InvalidSelectorError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "InvalidSelectorError";
|
|
|
|
this.status = "invalid selector";
|
|
|
|
};
|
|
|
|
InvalidSelectorError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-04-15 05:38:01 -07:00
|
|
|
this.InvalidSessionIdError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "InvalidSessionIdError";
|
|
|
|
this.status = "invalid session id";
|
|
|
|
this.code = 13;
|
|
|
|
};
|
|
|
|
InvalidSessionIdError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-17 07:27:20 -07:00
|
|
|
/**
|
|
|
|
* Creates an error message for a JavaScript error thrown during
|
|
|
|
* executeScript or executeAsyncScript.
|
|
|
|
*
|
|
|
|
* @param {Error} err
|
|
|
|
* An Error object passed to a catch block or a message.
|
|
|
|
* @param {string} fnName
|
|
|
|
* The name of the function to use in the stack trace message
|
|
|
|
* (e.g. execute_script).
|
|
|
|
* @param {string} file
|
|
|
|
* The filename of the test file containing the Marionette
|
|
|
|
* command that caused this error to occur.
|
|
|
|
* @param {number} line
|
|
|
|
* The line number of the above test file.
|
|
|
|
* @param {string=} script
|
|
|
|
* The JS script being executed in text form.
|
|
|
|
*/
|
|
|
|
this.JavaScriptError = function(err, fnName, file, line, script) {
|
|
|
|
let msg = String(err);
|
|
|
|
let trace = "";
|
|
|
|
|
|
|
|
if (fnName && line) {
|
|
|
|
trace += `${fnName} @${file}`;
|
|
|
|
if (line) {
|
|
|
|
trace += `, line ${line}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof err == "object" && "name" in err && "stack" in err) {
|
|
|
|
let jsStack = err.stack.split("\n");
|
|
|
|
let match = jsStack[0].match(/:(\d+):\d+$/);
|
|
|
|
let jsLine = match ? parseInt(match[1]) : 0;
|
|
|
|
if (script) {
|
|
|
|
let src = script.split("\n")[jsLine];
|
|
|
|
trace += "\n" +
|
|
|
|
"inline javascript, line " + jsLine + "\n" +
|
|
|
|
"src: \"" + src + "\"";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "JavaScriptError";
|
|
|
|
this.status = "javascript error";
|
|
|
|
this.stack = trace;
|
|
|
|
};
|
|
|
|
JavaScriptError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.NoAlertOpenError = function(msg) {
|
2015-03-17 07:27:20 -07:00
|
|
|
WebDriverError.call(this, msg);
|
2015-03-31 10:00:32 -07:00
|
|
|
this.name = "NoAlertOpenError";
|
|
|
|
this.status = "no such alert";
|
|
|
|
}
|
|
|
|
NoAlertOpenError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
|
|
|
this.NoSuchElementError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "NoSuchElementError";
|
|
|
|
this.status = "no such element";
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
2015-03-31 10:00:32 -07:00
|
|
|
NoSuchElementError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
|
|
|
this.NoSuchFrameError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "NoSuchFrameError";
|
|
|
|
this.status = "no such frame";
|
|
|
|
};
|
|
|
|
NoSuchFrameError.prototype = Object.create(WebDriverError.prototype);
|
2015-03-17 07:27:20 -07:00
|
|
|
|
|
|
|
this.NoSuchWindowError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "NoSuchWindowError";
|
|
|
|
this.status = "no such window";
|
|
|
|
};
|
|
|
|
NoSuchWindowError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
|
|
|
this.ScriptTimeoutError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "ScriptTimeoutError";
|
|
|
|
this.status = "script timeout";
|
|
|
|
};
|
|
|
|
ScriptTimeoutError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
|
|
|
this.SessionNotCreatedError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "SessionNotCreatedError";
|
|
|
|
this.status = "session not created";
|
2015-04-15 04:18:00 -07:00
|
|
|
};
|
2015-03-17 07:27:20 -07:00
|
|
|
SessionNotCreatedError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-04-15 04:18:00 -07:00
|
|
|
this.StaleElementReferenceError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "StaleElementReferenceError";
|
|
|
|
this.status = "stale element reference";
|
|
|
|
};
|
|
|
|
StaleElementReferenceError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.TimeoutError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "TimeoutError";
|
|
|
|
this.status = "timeout";
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
2015-03-31 10:00:32 -07:00
|
|
|
TimeoutError.prototype = Object.create(WebDriverError.prototype);
|
2015-03-17 07:27:20 -07:00
|
|
|
|
2015-04-20 05:53:51 -07:00
|
|
|
this.UnableToSetCookieError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "UnableToSetCookieError";
|
|
|
|
this.status = "unable to set cookie";
|
|
|
|
this.code = 25;
|
|
|
|
};
|
|
|
|
UnableToSetCookieError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
2015-03-31 10:00:32 -07:00
|
|
|
this.UnknownCommandError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "UnknownCommandError";
|
|
|
|
this.status = "unknown command";
|
2015-03-17 07:27:20 -07:00
|
|
|
};
|
2015-03-31 10:00:32 -07:00
|
|
|
UnknownCommandError.prototype = Object.create(WebDriverError.prototype);
|
|
|
|
|
|
|
|
this.UnknownError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "UnknownError";
|
|
|
|
this.status = "unknown error";
|
|
|
|
};
|
|
|
|
UnknownError.prototype = Object.create(WebDriverError.prototype);
|
2015-03-17 07:27:20 -07:00
|
|
|
|
|
|
|
this.UnsupportedOperationError = function(msg) {
|
|
|
|
WebDriverError.call(this, msg);
|
|
|
|
this.name = "UnsupportedOperationError";
|
|
|
|
this.status = "unsupported operation";
|
|
|
|
};
|
|
|
|
UnsupportedOperationError.prototype = Object.create(WebDriverError.prototype);
|