--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -10,16 +10,17 @@ let uuidGen = Cc["@mozilla.org/uuid-gene
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://marionette/content/simpletest.js");
loader.loadSubScript("chrome://marionette/content/common.js");
loader.loadSubScript("chrome://marionette/content/actions.js");
Cu.import("chrome://marionette/content/elements.js");
+Cu.import("chrome://marionette/content/error.js");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let utils = {};
utils.window = content;
// Load Event/ChromeUtils for use with JS scripts:
loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils);
loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils);
@@ -88,17 +89,17 @@ let modalHandler = function() {
};
/**
* Called when listener is first started up.
* The listener sends its unique window ID and its current URI to the actor.
* If the actor returns an ID, we start the listeners. Otherwise, nothing happens.
*/
function registerSelf() {
- let msg = {value: winUtil.outerWindowID}
+ let msg = {value: winUtil.outerWindowID};
// register will have the ID and a boolean describing if this is the main process or not
let register = sendSyncMessage("Marionette:register", msg);
if (register[0]) {
let {id, remotenessChange} = register[0][0];
listenerId = id;
if (typeof id != "undefined") {
// check if we're the main process
@@ -141,30 +142,61 @@ function emitTouchEventForIFrame(message
typeForUtils = domWindowUtils.TOUCH_CONTACT;
break;
}
domWindowUtils.sendNativeTouchPoint(identifier, typeForUtils,
Math.round(message.screenX * ratio), Math.round(message.screenY * ratio),
message.force, 90);
}
+function dispatch(fn) {
+ return function(msg) {
+ let id = msg.json.command_id;
+ try {
+ let rv;
+ if (typeof msg.json == "undefined" || msg.json instanceof Array) {
+ rv = fn.apply(null, msg.json);
+ } else {
+ rv = fn(msg.json);
+ }
+
+ if (typeof rv == "undefined") {
+ sendOk(id);
+ } else {
+ sendResponse({value: rv}, id);
+ }
+ } catch (e) {
+ sendError(e, id);
+ }
+ };
+}
+
/**
* Add a message listener that's tied to our listenerId.
*/
function addMessageListenerId(messageName, handler) {
addMessageListener(messageName + listenerId, handler);
}
/**
* Remove a message listener that's tied to our listenerId.
*/
function removeMessageListenerId(messageName, handler) {
removeMessageListener(messageName + listenerId, handler);
}
+let getElementSizeFn = dispatch(getElementSize);
+let getActiveElementFn = dispatch(getActiveElement);
+let clickElementFn = dispatch(clickElement);
+let getElementAttributeFn = dispatch(getElementAttribute);
+let getElementTextFn = dispatch(getElementText);
+let getElementTagNameFn = dispatch(getElementTagName);
+let getElementRectFn = dispatch(getElementRect);
+let isElementEnabledFn = dispatch(isElementEnabled);
+
/**
* Start all message listeners
*/
function startListeners() {
addMessageListenerId("Marionette:newSession", newSession);
addMessageListenerId("Marionette:executeScript", executeScript);
addMessageListenerId("Marionette:executeAsyncScript", executeAsyncScript);
addMessageListenerId("Marionette:executeJSScript", executeJSScript);
@@ -177,27 +209,27 @@ function startListeners() {
addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl);
addMessageListenerId("Marionette:getTitle", getTitle);
addMessageListenerId("Marionette:getPageSource", getPageSource);
addMessageListenerId("Marionette:goBack", goBack);
addMessageListenerId("Marionette:goForward", goForward);
addMessageListenerId("Marionette:refresh", refresh);
addMessageListenerId("Marionette:findElementContent", findElementContent);
addMessageListenerId("Marionette:findElementsContent", findElementsContent);
- addMessageListenerId("Marionette:getActiveElement", getActiveElement);
- addMessageListenerId("Marionette:clickElement", clickElement);
- addMessageListenerId("Marionette:getElementAttribute", getElementAttribute);
- addMessageListenerId("Marionette:getElementText", getElementText);
- addMessageListenerId("Marionette:getElementTagName", getElementTagName);
+ addMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
+ addMessageListenerId("Marionette:clickElement", clickElementFn);
+ addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
+ addMessageListenerId("Marionette:getElementText", getElementTextFn);
+ addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed);
addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty);
addMessageListenerId("Marionette:submitElement", submitElement);
- addMessageListenerId("Marionette:getElementSize", getElementSize);
- addMessageListenerId("Marionette:getElementRect", getElementRect);
- addMessageListenerId("Marionette:isElementEnabled", isElementEnabled);
+ addMessageListenerId("Marionette:getElementSize", getElementSizeFn); // deprecated
+ addMessageListenerId("Marionette:getElementRect", getElementRectFn);
+ addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
addMessageListenerId("Marionette:isElementSelected", isElementSelected);
addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
addMessageListenerId("Marionette:getElementLocation", getElementLocation); //deprecated
addMessageListenerId("Marionette:clearElement", clearElement);
addMessageListenerId("Marionette:switchToFrame", switchToFrame);
addMessageListenerId("Marionette:deleteSession", deleteSession);
addMessageListenerId("Marionette:sleepSession", sleepSession);
addMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
@@ -282,27 +314,27 @@ function deleteSession(msg) {
removeMessageListenerId("Marionette:getTitle", getTitle);
removeMessageListenerId("Marionette:getPageSource", getPageSource);
removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl);
removeMessageListenerId("Marionette:goBack", goBack);
removeMessageListenerId("Marionette:goForward", goForward);
removeMessageListenerId("Marionette:refresh", refresh);
removeMessageListenerId("Marionette:findElementContent", findElementContent);
removeMessageListenerId("Marionette:findElementsContent", findElementsContent);
- removeMessageListenerId("Marionette:getActiveElement", getActiveElement);
- removeMessageListenerId("Marionette:clickElement", clickElement);
- removeMessageListenerId("Marionette:getElementAttribute", getElementAttribute);
- removeMessageListenerId("Marionette:getElementText", getElementText);
- removeMessageListenerId("Marionette:getElementTagName", getElementTagName);
+ removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
+ removeMessageListenerId("Marionette:clickElement", clickElementFn);
+ removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
+ removeMessageListenerId("Marionette:getElementText", getElementTextFn);
+ removeMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed);
removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty);
removeMessageListenerId("Marionette:submitElement", submitElement);
- removeMessageListenerId("Marionette:getElementSize", getElementSize); //deprecated
- removeMessageListenerId("Marionette:getElementRect", getElementRect);
- removeMessageListenerId("Marionette:isElementEnabled", isElementEnabled);
+ removeMessageListenerId("Marionette:getElementSize", getElementSizeFn); // deprecated
+ removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
+ removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
removeMessageListenerId("Marionette:isElementSelected", isElementSelected);
removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
removeMessageListenerId("Marionette:getElementLocation", getElementLocation);
removeMessageListenerId("Marionette:clearElement", clearElement);
removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
removeMessageListenerId("Marionette:deleteSession", deleteSession);
removeMessageListenerId("Marionette:sleepSession", sleepSession);
removeMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
@@ -326,50 +358,52 @@ function deleteSession(msg) {
/*
* Helper methods
*/
/**
* Generic method to send a message to the server
*/
-function sendToServer(msg, value, command_id) {
- if (command_id) {
- value.command_id = command_id;
+function sendToServer(name, data, objs, id) {
+ if (!data) {
+ data = {}
}
- sendAsyncMessage(msg, value);
+ if (id) {
+ data.command_id = id;
+ }
+ sendAsyncMessage(name, data, objs);
}
/**
* Send response back to server
*/
function sendResponse(value, command_id) {
- sendToServer("Marionette:done", value, command_id);
+ sendToServer("Marionette:done", value, null, command_id);
}
/**
* Send ack back to server
*/
function sendOk(command_id) {
- sendToServer("Marionette:ok", {}, command_id);
+ sendToServer("Marionette:ok", null, null, command_id);
}
/**
* Send log message to server
*/
function sendLog(msg) {
- sendToServer("Marionette:log", { message: msg });
+ sendToServer("Marionette:log", {message: msg});
}
/**
* Send error message to server
*/
-function sendError(msg, code, stack, cmdId) {
- let payload = {message: msg, code: code, stack: stack};
- sendToServer("Marionette:error", payload, cmdId);
+function sendError(err, cmdId) {
+ sendToServer("Marionette:error", null, {error: err}, cmdId);
}
/**
* Clear test values after completion of test
*/
function resetValues() {
sandbox = null;
curFrame = content;
@@ -453,97 +487,90 @@ function createExecuteContentSandbox(aWi
});
}
else {
XPCOMUtils.defineLazyGetter(sandbox, 'SpecialPowers', function() {
return new SpecialPowers(aWindow);
});
}
- sandbox.asyncComplete = function sandbox_asyncComplete(value, status, stack, commandId) {
- if (commandId == asyncTestCommandId) {
+ sandbox.asyncComplete = function(obj, id) {
+ if (id == asyncTestCommandId) {
curFrame.removeEventListener("unload", onunload, false);
curFrame.clearTimeout(asyncTestTimeoutId);
if (inactivityTimeoutId != null) {
curFrame.clearTimeout(inactivityTimeoutId);
}
-
sendSyncMessage("Marionette:shareData",
- {log: elementManager.wrapValue(marionetteLogObj.getLogs())});
+ {log: elementManager.wrapValue(marionetteLogObj.getLogs())});
marionetteLogObj.clearLogs();
- if (status == 0){
+ if (error.isError(obj)) {
+ sendError(obj, id);
+ } else {
if (Object.keys(_emu_cbs).length) {
_emu_cbs = {};
- sendError("Emulator callback still pending when finish() called",
- 500, null, commandId);
+ sendError({message: "Emulator callback still pending when finish() called"}, id);
+ } else {
+ sendResponse({value: elementManager.wrapValue(obj)}, id);
}
- else {
- sendResponse({value: elementManager.wrapValue(value), status: status},
- commandId);
- }
- }
- else {
- sendError(value, status, stack, commandId);
}
asyncTestRunning = false;
asyncTestTimeoutId = undefined;
asyncTestCommandId = undefined;
inactivityTimeoutId = null;
}
};
sandbox.finish = function sandbox_finish() {
if (asyncTestRunning) {
- sandbox.asyncComplete(marionette.generate_results(), 0, null, sandbox.asyncTestCommandId);
+ sandbox.asyncComplete(marionette.generate_results(), sandbox.asyncTestCommandId);
} else {
return marionette.generate_results();
}
};
- sandbox.marionetteScriptFinished = function sandbox_marionetteScriptFinished(value) {
- return sandbox.asyncComplete(value, 0, null, sandbox.asyncTestCommandId);
- };
+ sandbox.marionetteScriptFinished = val =>
+ sandbox.asyncComplete(val, sandbox.asyncTestCommandId);
return sandbox;
}
/**
* Execute the given script either as a function body (executeScript)
- * or directly (for 'mochitest' like JS Marionette tests)
+ * or directly (for mochitest like JS Marionette tests).
*/
function executeScript(msg, directInject) {
// Set up inactivity timeout.
if (msg.json.inactivityTimeout) {
let setTimer = function() {
- inactivityTimeoutId = curFrame.setTimeout(function() {
- sendError('timed out due to inactivity', 28, null, asyncTestCommandId);
+ inactivityTimeoutId = curFrame.setTimeout(function() {
+ sendError(new ScriptTimeoutError("timed out due to inactivity"), asyncTestCommandId);
}, msg.json.inactivityTimeout);
};
setTimer();
- heartbeatCallback = function resetInactivityTimeout() {
+ heartbeatCallback = function() {
curFrame.clearTimeout(inactivityTimeoutId);
setTimer();
};
}
asyncTestCommandId = msg.json.command_id;
let script = msg.json.script;
if (msg.json.newSandbox || !sandbox) {
sandbox = createExecuteContentSandbox(curFrame,
msg.json.timeout);
if (!sandbox) {
- sendError("Could not create sandbox!", 500, null, asyncTestCommandId);
+ sendError(new WebDriverError("Could not create sandbox!"), asyncTestCommandId);
return;
}
- }
- else {
+ } else {
sandbox.asyncTestCommandId = asyncTestCommandId;
}
try {
if (directInject) {
if (importedScripts.exists()) {
let stream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
@@ -553,29 +580,28 @@ function executeScript(msg, directInject
script = data + script;
}
let res = Cu.evalInSandbox(script, sandbox, "1.8", "dummy file" ,0);
sendSyncMessage("Marionette:shareData",
{log: elementManager.wrapValue(marionetteLogObj.getLogs())});
marionetteLogObj.clearLogs();
if (res == undefined || res.passed == undefined) {
- sendError("Marionette.finish() not called", 17, null, asyncTestCommandId);
+ sendError(new JavaScriptError("Marionette.finish() not called"), asyncTestCommandId);
}
else {
sendResponse({value: elementManager.wrapValue(res)}, asyncTestCommandId);
}
}
else {
try {
sandbox.__marionetteParams = Cu.cloneInto(elementManager.convertWrappedArguments(
msg.json.args, curFrame), sandbox, { wrapReflectors: true });
- }
- catch(e) {
- sendError(e.message, e.code, e.stack, asyncTestCommandId);
+ } catch (e) {
+ sendError(e, asyncTestCommandId);
return;
}
script = "let __marionetteFunc = function(){" + script + "};" +
"__marionetteFunc.apply(null, __marionetteParams);";
if (importedScripts.exists()) {
let stream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
@@ -585,25 +611,24 @@ function executeScript(msg, directInject
script = data + script;
}
let res = Cu.evalInSandbox(script, sandbox, "1.8", "dummy file", 0);
sendSyncMessage("Marionette:shareData",
{log: elementManager.wrapValue(marionetteLogObj.getLogs())});
marionetteLogObj.clearLogs();
sendResponse({value: elementManager.wrapValue(res)}, asyncTestCommandId);
}
- }
- catch (e) {
- // 17 = JavascriptException
- let error = createStackMessage(e,
- "execute_script",
- msg.json.filename,
- msg.json.line,
- script);
- sendError(error[0], 17, error[1], asyncTestCommandId);
+ } catch (e) {
+ let err = new JavaScriptError(
+ e,
+ "execute_script",
+ msg.json.filename,
+ msg.json.line,
+ script);
+ sendError(err, asyncTestCommandId);
}
}
/**
* Sets the test name, used in logging messages.
*/
function setTestName(msg) {
marionetteTestName = msg.json.value;
@@ -637,77 +662,76 @@ function executeJSScript(msg) {
* For executeAsync, it will return a response when marionetteScriptFinished/arguments[arguments.length-1]
* method is called, or if it times out.
*/
function executeWithCallback(msg, useFinish) {
// Set up inactivity timeout.
if (msg.json.inactivityTimeout) {
let setTimer = function() {
inactivityTimeoutId = curFrame.setTimeout(function() {
- sandbox.asyncComplete('timed out due to inactivity', 28, null, asyncTestCommandId);
+ sandbox.asyncComplete(new ScriptTimeout("timed out due to inactivity"), asyncTestCommandId);
}, msg.json.inactivityTimeout);
};
setTimer();
- heartbeatCallback = function resetInactivityTimeout() {
+ heartbeatCallback = function() {
curFrame.clearTimeout(inactivityTimeoutId);
setTimer();
};
}
let script = msg.json.script;
asyncTestCommandId = msg.json.command_id;
onunload = function() {
- sendError("unload was called", 17, null, asyncTestCommandId);
+ sendError(new JavaScriptError("unload was called"), asyncTestCommandId);
};
curFrame.addEventListener("unload", onunload, false);
if (msg.json.newSandbox || !sandbox) {
sandbox = createExecuteContentSandbox(curFrame,
msg.json.timeout);
if (!sandbox) {
- sendError("Could not create sandbox!", 17, null, asyncTestCommandId);
+ sendError(new JavaScriptError("Could not create sandbox!"), asyncTestCommandId);
return;
}
}
else {
sandbox.asyncTestCommandId = asyncTestCommandId;
}
sandbox.tag = script;
// Error code 28 is scriptTimeout, but spec says execute_async should return 21 (Timeout),
// see http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/execute_async.
// However Selenium code returns 28, see
// http://code.google.com/p/selenium/source/browse/trunk/javascript/firefox-driver/js/evaluate.js.
// We'll stay compatible with the Selenium code.
asyncTestTimeoutId = curFrame.setTimeout(function() {
- sandbox.asyncComplete('timed out', 28, null, asyncTestCommandId);
+ sandbox.asyncComplete(new ScriptTimeoutError("timed out"), asyncTestCommandId);
}, msg.json.timeout);
originalOnError = curFrame.onerror;
- curFrame.onerror = function errHandler(errMsg, url, line) {
- sandbox.asyncComplete(errMsg, 17, "@" + url + ", line " + line, asyncTestCommandId);
+ curFrame.onerror = function errHandler(msg, url, line) {
+ sandbox.asyncComplete(new JavaScriptError(msg + "@" + url + ", line " + line), asyncTestCommandId);
curFrame.onerror = originalOnError;
};
let scriptSrc;
if (useFinish) {
if (msg.json.timeout == null || msg.json.timeout == 0) {
- sendError("Please set a timeout", 21, null, asyncTestCommandId);
+ sendError(new TimeoutError("Please set a timeout"), asyncTestCommandId);
}
scriptSrc = script;
}
else {
try {
sandbox.__marionetteParams = Cu.cloneInto(elementManager.convertWrappedArguments(
msg.json.args, curFrame), sandbox, { wrapReflectors: true });
- }
- catch(e) {
- sendError(e.message, e.code, e.stack, asyncTestCommandId);
+ } catch (e) {
+ sendError(e, asyncTestCommandId);
return;
}
scriptSrc = "__marionetteParams.push(marionetteScriptFinished);" +
"let __marionetteFunc = function() { " + script + "};" +
"__marionetteFunc.apply(null, __marionetteParams); ";
}
@@ -718,23 +742,23 @@ function executeWithCallback(msg, useFin
createInstance(Ci.nsIFileInputStream);
stream.init(importedScripts, -1, 0, 0);
let data = NetUtil.readInputStreamToString(stream, stream.available());
stream.close();
scriptSrc = data + scriptSrc;
}
Cu.evalInSandbox(scriptSrc, sandbox, "1.8", "dummy file", 0);
} catch (e) {
- // 17 = JavascriptException
- let error = createStackMessage(e,
- "execute_async_script",
- msg.json.filename,
- msg.json.line,
- scriptSrc);
- sandbox.asyncComplete(error[0], 17, error[1], asyncTestCommandId);
+ let err = new JavaScriptError(
+ e,
+ "execute_async_script",
+ msg.json.filename,
+ msg.json.line,
+ scriptSrc);
+ sandbox.asyncComplete(err, asyncTestCommandId);
}
}
/**
* This function creates a touch event given a touch type and a touch
*/
function emitTouchEvent(type, touch) {
if (!wasInterrupted()) {
@@ -851,35 +875,34 @@ function singleTap(msg) {
let command_id = msg.json.command_id;
try {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
let acc = accessibility.getAccessibleObject(el, true);
// after this block, the element will be scrolled into view
let visible = checkVisible(el, msg.json.corx, msg.json.cory);
checkVisibleAccessibility(acc, visible);
if (!visible) {
- sendError("Element is not currently visible and may not be manipulated", 11, null, command_id);
+ sendError(new ElementNotVisibleError("Element is not currently visible and may not be manipulated"), command_id);
return;
}
checkActionableAccessibility(acc);
if (!curFrame.document.createTouch) {
actions.mouseEventsOnly = true;
}
let c = coordinates(el, msg.json.corx, msg.json.cory);
if (!actions.mouseEventsOnly) {
let touchId = actions.nextTouchId++;
let touch = createATouch(el, c.x, c.y, touchId);
emitTouchEvent('touchstart', touch);
emitTouchEvent('touchend', touch);
}
actions.mouseTap(el.ownerDocument, c.x, c.y);
- sendOk(msg.json.command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, msg.json.command_id);
+ sendOk(command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Check if the element's unavailable accessibility state matches the enabled
* state
* @param nsIAccessible object
* @param Boolean enabled element's enabled state
@@ -954,37 +977,33 @@ function createATouch(el, corx, cory, to
* Function to start action chain on one finger
*/
function actionChain(msg) {
let command_id = msg.json.command_id;
let args = msg.json.chain;
let touchId = msg.json.nextId;
let callbacks = {};
- callbacks.onSuccess = (value) => {
- sendResponse(value, command_id);
- };
- callbacks.onError = (message, code, trace) => {
- sendError(message, code, trace, msg.json.command_id);
- };
+ callbacks.onSuccess = value => sendResponse(value, command_id);
+ callbacks.onError = err => sendError(err, command_id);
let touchProvider = {};
touchProvider.createATouch = createATouch;
touchProvider.emitTouchEvent = emitTouchEvent;
try {
actions.dispatchActions(
args,
touchId,
curFrame,
elementManager,
callbacks,
touchProvider);
} catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ sendError(e, command_id);
}
}
/**
* Function to emit touch events which allow multi touch on the screen
* @param type represents the type of event, touch represents the current touch,touches are all pending touches
*/
function emitMultiEvents(type, touch, touches) {
@@ -1139,19 +1158,18 @@ function multiAction(msg) {
}
concurrentEvent.push(row);
}
// now concurrent event is made of sets where each set contain a list of actions that need to be fired.
// note: each action belongs to a different finger
// pendingTouches keeps track of current touches that's on the screen
let pendingTouches = [];
setDispatch(concurrentEvent, pendingTouches, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, msg.json.command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/*
* This implements the latter part of a get request (for the case we need to resume one
* when a remoteness update happens in the middle of a navigate request). This is most of
* of the work of a navigate request, but doesn't assume DOMContentLoaded is yet to fire.
*/
@@ -1173,29 +1191,27 @@ function pollForReadyState(msg, start, c
if (curFrame.document.readyState == "complete") {
callback();
sendOk(command_id);
} else if (curFrame.document.readyState == "interactive" &&
aboutErrorRegex.exec(curFrame.document.baseURI) &&
!curFrame.document.baseURI.startsWith(url)) {
// We have reached an error url without requesting it.
callback();
- sendError("Error loading page", 13, null, command_id);
+ sendError(new UnknownError("Error loading page"), command_id);
} else if (curFrame.document.readyState == "interactive" &&
curFrame.document.baseURI.startsWith("about:")) {
callback();
sendOk(command_id);
} else {
navTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
}
- }
- else {
+ } else {
callback();
- sendError("Error loading page, timed out (checkLoad)", 21, null,
- command_id);
+ sendError(new TimeoutError("Error loading page, timed out (checkLoad)"), command_id);
}
}
checkLoad();
}
/**
* Navigate to the given URL. The operation will be performed on the
* current browser context, and handles the case where we navigate
@@ -1215,18 +1231,17 @@ function get(msg) {
removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
onDOMContentLoaded = null;
});
}
};
function timerFunc() {
removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- sendError("Error loading page, timed out (onDOMContentLoaded)", 21,
- null, msg.json.command_id);
+ sendError(new TimeoutError("Error loading page, timed out (onDOMContentLoaded)"), msg.json.command_id);
}
if (msg.json.pageTimeout != null) {
navTimer.initWithCallback(timerFunc, msg.json.pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
}
addEventListener("DOMContentLoaded", onDOMContentLoaded, false);
curFrame.location = msg.json.url;
}
@@ -1301,138 +1316,129 @@ function refresh(msg) {
}
/**
* Find an element in the document using requested search strategy
*/
function findElementContent(msg) {
let command_id = msg.json.command_id;
try {
- let on_success = function(el, cmd_id) { sendResponse({value: el}, cmd_id) };
- let on_error = function(e, cmd_id) { sendError(e.message, e.code, null, cmd_id); };
+ let onSuccess = (el, id) => sendResponse({value: el}, id);
+ let onError = (err, id) => sendError(err, id);
elementManager.find(curFrame, msg.json, msg.json.searchTimeout,
- false /* all */, on_success, on_error, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ false /* all */, onSuccess, onError, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Find elements in the document using requested search strategy
*/
function findElementsContent(msg) {
let command_id = msg.json.command_id;
try {
- let on_success = function(els, cmd_id) { sendResponse({value: els}, cmd_id); };
- let on_error = function(e, cmd_id) { sendError(e.message, e.code, null, cmd_id); };
+ let onSuccess = (els, id) => sendResponse({value: els}, id);
+ let onError = (err, id) => sendError(err, id);
elementManager.find(curFrame, msg.json, msg.json.searchTimeout,
- true /* all */, on_success, on_error, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ true /* all */, onSuccess, onError, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
- * Find and return the active element on the page
+ * Find and return the active element on the page.
+ *
+ * @return {WebElement}
+ * Reference to web element.
*/
-function getActiveElement(msg) {
- let command_id = msg.json.command_id;
- var element = curFrame.document.activeElement;
- var id = elementManager.addToKnownElements(element);
- sendResponse({value: id}, command_id);
+function getActiveElement() {
+ let el = curFrame.document.activeElement;
+ return elementManager.addToKnownElements(el);
}
/**
- * Send click event to element
+ * Send click event to element.
+ *
+ * @param {WebElement} id
+ * Reference to the web element to click.
*/
-function clickElement(msg) {
- let command_id = msg.json.command_id;
- let el;
- try {
- el = elementManager.getKnownElement(msg.json.id, curFrame);
- let acc = accessibility.getAccessibleObject(el, true);
- let visible = checkVisible(el);
- checkVisibleAccessibility(acc, visible);
- if (visible) {
- checkActionableAccessibility(acc);
- if (utils.isElementEnabled(el)) {
- utils.synthesizeMouseAtCenter(el, {}, el.ownerDocument.defaultView)
- }
- else {
- sendError("Element is not Enabled", 12, null, command_id)
- }
- }
- else {
- sendError("Element is not visible", 11, null, command_id)
- }
- sendOk(command_id);
+function clickElement(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ let acc = accessibility.getAccessibleObject(el, true);
+ let visible = checkVisible(el);
+ checkVisibleAccessibility(acc, visible);
+ if (!visible) {
+ throw new ElementNotVisibleError("Element is not visible");
}
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ checkActionableAccessibility(acc);
+ if (utils.isElementEnabled(el)) {
+ utils.synthesizeMouseAtCenter(el, {}, el.ownerDocument.defaultView);
+ } else {
+ throw new InvalidElementStateError("Element is not Enabled");
}
}
/**
- * Get a given attribute of an element
+ * Get a given attribute of an element.
+ *
+ * @param {WebElement} id
+ * Reference to the web element to get the attribute of.
+ * @param {string} name
+ * Name of the attribute.
+ *
+ * @return {string}
+ * The value of the attribute.
*/
-function getElementAttribute(msg) {
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- sendResponse({value: utils.getElementAttribute(el, msg.json.name)},
- command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
+function getElementAttribute(id, name) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ return utils.getElementAttribute(el, name);
}
/**
* Get the text of this element. This includes text from child elements.
+ *
+ * @param {WebElement} id
+ * Reference to web element.
+ *
+ * @return {string}
+ * Text of element.
*/
-function getElementText(msg) {
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- sendResponse({value: utils.getElementText(el)}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
+function getElementText(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ return utils.getElementText(el);
}
/**
* Get the tag name of an element.
+ *
+ * @param {WebElement} id
+ * Reference to web element.
+ *
+ * @return {string}
+ * Tag name of element.
*/
-function getElementTagName(msg) {
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- sendResponse({value: el.tagName.toLowerCase()}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
+function getElementTagName(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ return el.tagName.toLowerCase();
}
/**
* Check if element is displayed
*/
function isElementDisplayed(msg) {
let command_id = msg.json.command_id;
try {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
let displayed = utils.isElementDisplayed(el);
checkVisibleAccessibility(accessibility.getAccessibleObject(el), displayed);
sendResponse({value: displayed}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Return the property of the computed style of an element
*
* @param object aRequest
* 'element' member holds the reference id to
@@ -1441,19 +1447,18 @@ function isElementDisplayed(msg) {
*/
function getElementValueOfCssProperty(msg){
let command_id = msg.json.command_id;
let propertyName = msg.json.propertyName;
try {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
sendResponse({value: curFrame.document.defaultView.getComputedStyle(el, null).getPropertyValue(propertyName)},
command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Submit a form on a content page by either using form or element in a form
* @param object msg
* 'json' JSON object containing 'id' member of the element
*/
@@ -1462,90 +1467,85 @@ function submitElement (msg) {
try {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
while (el.parentNode != null && el.tagName.toLowerCase() != 'form') {
el = el.parentNode;
}
if (el.tagName && el.tagName.toLowerCase() == 'form') {
el.submit();
sendOk(command_id);
- }
- else {
- sendError("Element is not a form element or in a form", 7, null, command_id);
+ } else {
+ sendError(new NoSuchElementError("Element is not a form element or in a form"), command_id);
}
-
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
-}
-
-/**
- * Get the size of the element and return it
- */
-function getElementSize(msg){
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- let clientRect = el.getBoundingClientRect();
- sendResponse({value: {width: clientRect.width, height: clientRect.height}},
- command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
- * Get the size of the element and return it
+ * Get the size of the element.
+ *
+ * @param {WebElement} id
+ * Web element reference.
+ *
+ * @return {Object.<string, number>}
+ * The width/height dimensions of th element.
*/
-function getElementRect(msg){
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- let clientRect = el.getBoundingClientRect();
- sendResponse({value: {x: clientRect.x + curFrame.pageXOffset,
- y: clientRect.y + curFrame.pageYOffset,
- width: clientRect.width,
- height: clientRect.height}},
- command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
+function getElementSize(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ let clientRect = el.getBoundingClientRect();
+ return {width: clientRect.width, height: clientRect.height};
}
/**
- * Check if element is enabled
+ * Get the size of the element.
+ *
+ * @param {WebElement} id
+ * Reference to web element.
+ *
+ * @return {Object.<string, number>}
+ * The x, y, width, and height properties of the element.
*/
-function isElementEnabled(msg) {
- let command_id = msg.json.command_id;
- try {
- let el = elementManager.getKnownElement(msg.json.id, curFrame);
- let enabled = utils.isElementEnabled(el);
- checkEnabledStateAccessibility(accessibility.getAccessibleObject(el),
- enabled);
- sendResponse({value: enabled}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
- }
+function getElementRect(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ let clientRect = el.getBoundingClientRect();
+ return {
+ x: clientRect.x + curFrame.pageXOffset,
+ y: clientRect.y + curFrame.pageYOffset,
+ width: clientRect.width,
+ height: clientRect.height
+ };
+}
+
+/**
+ * Check if element is enabled.
+ *
+ * @param {WebElement} id
+ * Reference to web element.
+ *
+ * @return {boolean}
+ * True if enabled, false otherwise.
+ */
+function isElementEnabled(id) {
+ let el = elementManager.getKnownElement(id, curFrame);
+ let enabled = utils.isElementEnabled(el);
+ checkEnabledStateAccessibility(accessibility.getAccessibleObject(el), enabled);
+ return enabled;
}
/**
* Check if element is selected
*/
function isElementSelected(msg) {
let command_id = msg.json.command_id;
try {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
sendResponse({value: utils.isElementSelected(el)}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Send keys to element
*/
function sendKeysToElement(msg) {
let command_id = msg.json.command_id;
@@ -1593,19 +1593,18 @@ function getElementLocation(msg) {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
let rect = el.getBoundingClientRect();
let location = {};
location.x = rect.left;
location.y = rect.top;
sendResponse({value: location}, command_id);
- }
- catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
}
/**
* Clear the text of an element
*/
function clearElement(msg) {
let command_id = msg.json.command_id;
@@ -1613,34 +1612,34 @@ function clearElement(msg) {
let el = elementManager.getKnownElement(msg.json.id, curFrame);
if (el.type == "file") {
el.value = null;
} else {
utils.clearElement(el);
}
sendOk(command_id);
} catch (e) {
- sendError(e.message, e.code, e.stack, command_id);
+ sendError(e, command_id);
}
}
/**
* Switch to frame given either the server-assigned element id,
* its index in window.frames, or the iframe's name or id.
*/
function switchToFrame(msg) {
let command_id = msg.json.command_id;
function checkLoad() {
let errorRegex = /about:.+(error)|(blocked)\?/;
if (curFrame.document.readyState == "complete") {
sendOk(command_id);
return;
- }
- else if (curFrame.document.readyState == "interactive" && errorRegex.exec(curFrame.document.baseURI)) {
- sendError("Error loading page", 13, null, command_id);
+ } else if (curFrame.document.readyState == "interactive" &&
+ errorRegex.exec(curFrame.document.baseURI)) {
+ sendError(new UnknownError("Error loading page"), command_id);
return;
}
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
}
let foundFrame = null;
let frames = [];
let parWindow = null;
// Check of the curFrame reference is dead
@@ -1670,19 +1669,18 @@ function switchToFrame(msg) {
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
return;
}
if (msg.json.element != undefined) {
if (elementManager.seenItems[msg.json.element] != undefined) {
let wantedFrame;
try {
wantedFrame = elementManager.getKnownElement(msg.json.element, curFrame); //Frame Element
- }
- catch(e) {
- sendError(e.message, e.code, e.stack, command_id);
+ } catch (e) {
+ sendError(e, command_id);
}
if (frames.length > 0) {
for (let i = 0; i < frames.length; i++) {
// use XPCNativeWrapper to compare elements; see bug 834266
if (XPCNativeWrapper(frames[i].frameElement) == XPCNativeWrapper(wantedFrame)) {
curFrame = frames[i].frameElement;
foundFrame = i;
@@ -1730,18 +1728,19 @@ function switchToFrame(msg) {
let iframes = curFrame.document.getElementsByTagName("iframe");
if (msg.json.id >= 0 && msg.json.id < iframes.length) {
curFrame = iframes[msg.json.id];
foundFrame = msg.json.id;
}
}
}
}
+
if (foundFrame === null) {
- sendError("Unable to locate frame: " + (msg.json.id || msg.json.element), 8, null, command_id);
+ sendError(new NoSuchFrameError("Unable to locate frame: " + (msg.json.id || msg.json.element)), command_id);
return true;
}
sandbox = null;
// send a synchronous message to let the server update the currently active
// frame element (for getActiveFrame)
let frameValue = elementManager.wrapValue(curFrame.wrappedJSObject)['ELEMENT'];
@@ -1772,40 +1771,39 @@ function addCookie(msg) {
var thePresent = new Date(Date.now());
date.setYear(thePresent.getFullYear() + 20);
cookie.expiry = date.getTime() / 1000; // Stored in seconds.
}
if (!cookie.domain) {
var location = curFrame.document.location;
cookie.domain = location.hostname;
- }
- else {
+ } else {
var currLocation = curFrame.location;
var currDomain = currLocation.host;
if (currDomain.indexOf(cookie.domain) == -1) {
- sendError("You may only set cookies for the current domain", 24, null, msg.json.command_id);
+ sendError(new InvalidCookieDomainError("You may only set cookies for the current domain"), msg.json.command_id);
}
}
// The cookie's domain may include a port. Which is bad. Remove it
// We'll catch ip6 addresses by mistake. Since no-one uses those
// this will be okay for now. See Bug 814416
if (cookie.domain.match(/:\d+$/)) {
cookie.domain = cookie.domain.replace(/:\d+$/, '');
}
var document = curFrame.document;
if (!document || !document.contentType.match(/html/i)) {
- sendError('You may only set cookies on html documents', 25, null, msg.json.command_id);
+ sendError(new UnableToSetCookie("You may only set cookies on html documents"), msg.json.command_id);
}
let added = sendSyncMessage("Marionette:addCookie", {value: cookie});
if (added[0] !== true) {
- sendError("Error setting cookie", 13, null, msg.json.command_id);
+ sendError(new UnknownError("Error setting cookie"), msg.json.command_id);
return;
}
sendOk(msg.json.command_id);
}
/**
* Get all cookies for the current domain.
*/
@@ -1836,34 +1834,34 @@ function getCookies(msg) {
*/
function deleteCookie(msg) {
let toDelete = msg.json.name;
let cookies = getVisibleCookies(curFrame.location);
for (let cookie of cookies) {
if (cookie.name == toDelete) {
let deleted = sendSyncMessage("Marionette:deleteCookie", {value: cookie});
if (deleted[0] !== true) {
- sendError("Could not delete cookie: " + msg.json.name, 13, null, msg.json.command_id);
+ sendError(new UnknownError("Could not delete cookie: " + msg.json.name), msg.json.command_id);
return;
}
}
}
sendOk(msg.json.command_id);
}
/**
* Delete all the visibile cookies on a page
*/
function deleteAllCookies(msg) {
let cookies = getVisibleCookies(curFrame.location);
for (let cookie of cookies) {
let deleted = sendSyncMessage("Marionette:deleteCookie", {value: cookie});
if (!deleted[0]) {
- sendError("Could not delete cookie: " + JSON.stringify(cookie), 13, null, msg.json.command_id);
+ sendError(new UnknownError("Could not delete cookie: " + JSON.stringify(cookie)), msg.json.command_id);
return;
}
}
sendOk(msg.json.command_id);
}
/**
* Get all the visible cookies from a location
@@ -1907,19 +1905,18 @@ function emulatorCmdResult(msg) {
}
let cb = _emu_cbs[message.id];
delete _emu_cbs[message.id];
if (!cb) {
return;
}
try {
cb(message.result);
- }
- catch(e) {
- sendError(e.message, e.code, e.stack, -1);
+ } catch (e) {
+ sendError(e, -1);
return;
}
}
function importScript(msg) {
let command_id = msg.json.command_id;
let file;
if (importedScripts.exists()) {