Backed out changeset 043a824dd7b7 (bug 1153832) for mass Mn failure.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 15 Apr 2015 12:58:51 -0400
changeset 239270 e026141c2ce9bc4e8ca6ed331f19c66d12b0d7ef
parent 239269 bd9cb02d4da8d2c047fe2b7c588b7cf9b73358f3
child 239271 f97fc9fef527d6e737aecd12be567ae387e9de6f
push id58479
push userryanvm@gmail.com
push dateWed, 15 Apr 2015 16:58:49 +0000
treeherdermozilla-inbound@e026141c2ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1153832
milestone40.0a1
backs out043a824dd7b749192a8c7ec3f1a8d3ba4d2619d0
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 043a824dd7b7 (bug 1153832) for mass Mn failure. CLOSED TREE
testing/marionette/driver.js
testing/marionette/elements.js
testing/marionette/error.js
testing/marionette/listener.js
testing/marionette/sendkeys.js
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -150,17 +150,18 @@ ListenerProxy.prototype.__noSuchMethod__
       this.mm.addMessageListener(val, removeListeners(val, valListener));
       this.mm.addMessageListener(err, removeListeners(err, errListener));
     };
     listeners.remove = () =>
         listeners.map(l => this.mm.removeMessageListener(l[0], l[1]));
 
     let okListener = () => resolve();
     let valListener = msg => resolve(msg.json.value);
-    let errListener = msg => reject(msg.objects.error);
+    let errListener = msg => reject(
+        "error" in msg.objects ? msg.objects.error : msg.json);
 
     let handleDialog = function(subject, topic) {
       listeners.remove();
       modal.removeHandler(handleDialog);
       this.sendAsync("cancelRequest");
       resolve();
     }.bind(this);
 
@@ -2056,17 +2057,17 @@ GeckoDriver.prototype.clickElement = fun
       break;
 
     case Context.CONTENT:
       // We need to protect against the click causing an OOP frame to close.
       // This fires the mozbrowserclose event when it closes so we need to
       // listen for it and then just send an error back. The person making the
       // call should be aware something isnt right and handle accordingly
       this.addFrameCloseListener("click");
-      yield this.listener.clickElement(id);
+      yield this.listener.clickElement({id: id});
       break;
   }
 };
 
 /**
  * Get a given attribute of an element.
  *
  * @param {string} id
@@ -2080,17 +2081,17 @@ GeckoDriver.prototype.getElementAttribut
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       resp.value = utils.getElementAttribute(el, name);
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.getElementAttribute(id, name);
+      resp.value = yield this.listener.getElementAttribute({id: id, name: name});
       break;
   }
 };
 
 /**
  * Get the text of an element, if any.  Includes the text of all child
  * elements.
  *
@@ -2106,17 +2107,17 @@ GeckoDriver.prototype.getElementText = f
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       let lines = [];
       this.getVisibleText(el, lines);
       resp.value = lines.join("\n");
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.getElementText(id);
+      resp.value = yield this.listener.getElementText({id: id});
       break;
   }
 };
 
 /**
  * Get the tag name of the element.
  *
  * @param {string} id
@@ -2128,17 +2129,17 @@ GeckoDriver.prototype.getElementTagName 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       resp.value = el.tagName.toLowerCase();
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.getElementTagName(id);
+      resp.value = yield this.listener.getElementTagName({id: id});
       break;
   }
 };
 
 /**
  * Check if element is displayed.
  *
  * @param {string} id
@@ -2218,17 +2219,17 @@ GeckoDriver.prototype.isElementEnabled =
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       resp.value = !(!!el.disabled);
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.isElementEnabled(id);
+      resp.value = yield this.listener.isElementEnabled({id: id});
       break;
   }
 },
 
 /**
  * Check if element is selected.
  *
  * @param {string} id
@@ -2264,17 +2265,17 @@ GeckoDriver.prototype.getElementSize = f
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, win);
       let rect = el.getBoundingClientRect();
       resp.value = {width: rect.width, height: rect.height};
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.getElementSize(id);
+      resp.value = yield this.listener.getElementSize({id: id});
       break;
   }
 };
 
 GeckoDriver.prototype.getElementRect = function(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
@@ -2286,17 +2287,17 @@ GeckoDriver.prototype.getElementRect = f
         x: rect.x + win.pageXOffset,
         y: rect.y + win.pageYOffset,
         width: rect.width,
         height: rect.height
       };
       break;
 
     case Context.CONTENT:
-      resp.value = yield this.listener.getElementRect(id);
+      resp.value = yield this.listener.getElementRect({id: id});
       break;
   }
 };
 
 /**
  * Send key presses to element after focusing on it.
  *
  * @param {string} id
--- a/testing/marionette/elements.js
+++ b/testing/marionette/elements.js
@@ -1,16 +1,13 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* 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/. */
 
-let {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
 /**
  * The ElementManager manages DOM references and interactions with elements.
  * According to the WebDriver spec (http://code.google.com/p/selenium/wiki/JsonWireProtocol), the
  * server sends the client an element reference, and maintains the map of reference to element.
  * The client uses this reference when querying/interacting with the element, and the
  * server uses maps this reference to the actual element when it executes the command.
  */
 
@@ -26,30 +23,36 @@ this.EXPORTED_SYMBOLS = [
   "TAG",
   "XPATH",
   "ANON",
   "ANON_ATTRIBUTE"
 ];
 
 const DOCUMENT_POSITION_DISCONNECTED = 1;
 
-const uuidGen = Components.classes["@mozilla.org/uuid-generator;1"]
-    .getService(Components.interfaces.nsIUUIDGenerator);
+let uuidGen = Components.classes["@mozilla.org/uuid-generator;1"]
+             .getService(Components.interfaces.nsIUUIDGenerator);
 
 this.CLASS_NAME = "class name";
 this.SELECTOR = "css selector";
 this.ID = "id";
 this.NAME = "name";
 this.LINK_TEXT = "link text";
 this.PARTIAL_LINK_TEXT = "partial link text";
 this.TAG = "tag name";
 this.XPATH = "xpath";
 this.ANON= "anon";
 this.ANON_ATTRIBUTE = "anon attribute";
 
+function ElementException(msg, num, stack) {
+  this.message = msg;
+  this.code = num;
+  this.stack = stack;
+}
+
 this.Accessibility = function Accessibility() {
   // A flag indicating whether the accessibility issue should be logged or cause
   // an exception. Default: log to stdout.
   this.strict = false;
   // An interface for in-process accessibility clients
   // Note: we access it lazily to not enable accessibility when it is not needed
   Object.defineProperty(this, 'accessibleRetrieval', {
     configurable: true,
@@ -177,17 +180,17 @@ Accessibility.prototype = {
    * Send an error message or log the error message in the log
    * @param String message
    */
   handleErrorMessage(message) {
     if (!message) {
       return;
     }
     if (this.strict) {
-      throw new ElementNotAccessibleError(message);
+      throw new ElementException(message, 56, null);
     }
     dump(Date.now() + " Marionette: " + message);
   }
 };
 
 this.ElementManager = function ElementManager(notSupported) {
   this.seenItems = {};
   this.timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
@@ -216,27 +219,29 @@ ElementManager.prototype = {
   * @return string
   *        Returns the server-assigned reference ID
   */
   addToKnownElements: function EM_addToKnownElements(element) {
     for (let i in this.seenItems) {
       let foundEl = null;
       try {
         foundEl = this.seenItems[i].get();
-      } catch (e) {}
+      }
+      catch(e) {}
       if (foundEl) {
         if (XPCNativeWrapper(foundEl) == XPCNativeWrapper(element)) {
           return i;
         }
-      } else {
-        // cleanup reference to GC'd element
+      }
+      else {
+        //cleanup reference to GC'd element
         delete this.seenItems[i];
       }
     }
-    let id = uuidGen.generateUUID().toString();
+    var id = uuidGen.generateUUID().toString();
     this.seenItems[id] = Components.utils.getWeakReference(element);
     return id;
   },
 
   /**
    * Retrieve element from its unique ID
    *
    * @param String id
@@ -245,34 +250,33 @@ ElementManager.prototype = {
    *        The window that contains the element
    *
    * @returns nsIDOMElement
    *        Returns the element or throws Exception if not found
    */
   getKnownElement: function EM_getKnownElement(id, win) {
     let el = this.seenItems[id];
     if (!el) {
-      throw new JavaScriptError("Element has not been seen before. Id given was " + id);
+      throw new ElementException("Element has not been seen before. Id given was " + id, 17, null);
     }
     try {
       el = el.get();
     }
     catch(e) {
       el = null;
       delete this.seenItems[id];
     }
     // use XPCNativeWrapper to compare elements; see bug 834266
     let wrappedWin = XPCNativeWrapper(win);
     if (!el ||
         !(XPCNativeWrapper(el).ownerDocument == wrappedWin.document) ||
         (XPCNativeWrapper(el).compareDocumentPosition(wrappedWin.document.documentElement) &
          DOCUMENT_POSITION_DISCONNECTED)) {
-      throw new StaleElementReferenceError(
-          "The element reference is stale. Either the element " +
-          "is no longer attached to the DOM or the page has been refreshed.");
+      throw new ElementException("The element reference is stale. Either the element " +
+                                 "is no longer attached to the DOM or the page has been refreshed.", 10, null);
     }
     return el;
   },
 
   /**
    * Convert values to primitives that can be transported over the
    * Marionette protocol.
    *
@@ -360,19 +364,18 @@ ElementManager.prototype = {
             converted.push(this.convertWrappedArguments(args[i], win));
           }
         }
         else if (((typeof(args[this.elementKey]) === 'string') && args.hasOwnProperty(this.elementKey)) ||
                  ((typeof(args[this.w3cElementKey]) === 'string') &&
                      args.hasOwnProperty(this.w3cElementKey))) {
           let elementUniqueIdentifier = args[this.w3cElementKey] ? args[this.w3cElementKey] : args[this.elementKey];
           converted = this.getKnownElement(elementUniqueIdentifier,  win);
-          if (converted == null) {
-            throw new WebDriverError(`Unknown element: ${elementUniqueIdentifier}`);
-          }
+          if (converted == null)
+            throw new ElementException("Unknown element: " + elementUniqueIdentifier, 500, null);
         }
         else {
           converted = {};
           for (let prop in args) {
             converted[prop] = this.convertWrappedArguments(args[prop], win);
           }
         }
         break;
@@ -435,17 +438,17 @@ ElementManager.prototype = {
    * @return nsIDOMElement or list of nsIDOMElements
    *        Returns the element(s) by calling the on_success function.
    */
   find: function EM_find(win, values, searchTimeout, all, on_success, on_error, command_id) {
     let startTime = values.time ? values.time : new Date().getTime();
     let startNode = (values.element != undefined) ?
                     this.getKnownElement(values.element, win) : win.document;
     if (this.elementStrategies.indexOf(values.using) < 0) {
-      throw new InvalidSelectorError(`No such strategy: ${values.using}`);
+      throw new ElementException("No such strategy.", 32, null);
     }
     let found = all ? this.findElements(values.using, values.value, win.document, startNode) :
                       this.findElement(values.using, values.value, win.document, startNode);
     let type = Object.prototype.toString.call(found);
     let isArrayLike = ((type == '[object Array]') || (type == '[object HTMLCollection]') || (type == '[object NodeList]'));
     if (found == null || (isArrayLike && found.length <= 0)) {
       if (!searchTimeout || new Date().getTime() - startTime > searchTimeout) {
         if (all) {
@@ -453,17 +456,17 @@ ElementManager.prototype = {
         } else {
           // Format message depending on strategy if necessary
           let message = "Unable to locate element: " + values.value;
           if (values.using == ANON) {
             message = "Unable to locate anonymous children";
           } else if (values.using == ANON_ATTRIBUTE) {
             message = "Unable to locate anonymous element: " + JSON.stringify(values.value);
           }
-          on_error(new NoSuchElementError(message), command_id);
+          on_error({message: message, code: 7}, command_id);
         }
       } else {
         values.time = startTime;
         this.timer.initWithCallback(this.find.bind(this, win, values,
                                                    searchTimeout, all,
                                                    on_success, on_error,
                                                    command_id),
                                     100,
@@ -586,17 +589,17 @@ ElementManager.prototype = {
           element = element[0];
         }
         break;
       case ANON_ATTRIBUTE:
         let attr = Object.keys(value)[0];
         element = rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]);
         break;
       default:
-        throw new WebDriverError("No such strategy");
+        throw new ElementException("No such strategy", 500, null);
     }
     return element;
   },
 
   /**
    * Helper method to find. Finds all element using find's criteria
    *
    * @param string using
@@ -653,13 +656,13 @@ ElementManager.prototype = {
       case ANON_ATTRIBUTE:
         let attr = Object.keys(value)[0];
         let el = rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]);
         if (el != null) {
           elements = [el];
         }
         break;
       default:
-        throw new WebDriverError("No such strategy");
+        throw new ElementException("No such strategy", 500, null);
     }
     return elements;
   },
 }
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -2,31 +2,28 @@
  * 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";
 
 const {utils: Cu} = Components;
 
 const errors = [
-  "ElementNotAccessibleError",
   "ElementNotVisibleError",
   "FrameSendFailureError",
   "FrameSendNotInitializedError",
   "IllegalArgumentError",
   "InvalidElementStateError",
-  "InvalidSelectorError",
   "JavaScriptError",
   "NoAlertOpenError",
   "NoSuchElementError",
   "NoSuchFrameError",
   "NoSuchWindowError",
   "ScriptTimeoutError",
   "SessionNotCreatedError",
-  "StaleElementReferenceError",
   "TimeoutError",
   "UnknownCommandError",
   "UnknownError",
   "UnsupportedOperationError",
   "WebDriverError",
 ];
 
 this.EXPORTED_SYMBOLS = ["error"].concat(errors);
@@ -37,16 +34,21 @@ error.toJSON = function(err) {
   return {
     message: err.message,
     stacktrace: err.stack || null,
     status: err.code
   };
 };
 
 /**
+ * Gets WebDriver error by its Selenium status code number.
+ */
+error.byCode = n => lookup.get(n);
+
+/**
  * Determines if the given status code is successful.
  */
 error.isSuccess = code => code === 0;
 
 /**
  * Old-style errors are objects that has all of the properties
  * "message", "code", and "stack".
  *
@@ -123,24 +125,16 @@ this.WebDriverError = function(msg) {
   Error.call(this, msg);
   this.name = "WebDriverError";
   this.message = msg;
   this.status = "webdriver error";
   this.code = 500;  // overridden
 };
 WebDriverError.prototype = Object.create(Error.prototype);
 
-this.ElementNotAccessibleError = function(msg) {
-  WebDriverError.call(this, msg);
-  this.name = "ElementNotAccessibleError";
-  this.status = "element not accessible";
-  this.code = 56;
-};
-ElementNotAccessibleError.prototype = Object.create(WebDriverError.prototype);
-
 this.ElementNotVisibleError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "ElementNotVisibleError";
   this.status = "element not visible";
   this.code = 11;
 };
 ElementNotVisibleError.prototype = Object.create(WebDriverError.prototype);
 
@@ -177,24 +171,16 @@ IllegalArgumentError.prototype = Object.
 this.InvalidElementStateError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "InvalidElementStateError";
   this.status = "invalid element state";
   this.code = 12;
 };
 InvalidElementStateError.prototype = Object.create(WebDriverError.prototype);
 
-this.InvalidSelectorError = function(msg) {
-  WebDriverError.call(this, msg);
-  this.name = "InvalidSelectorError";
-  this.status = "invalid selector";
-  this.code = 32;
-};
-InvalidSelectorError.prototype = Object.create(WebDriverError.prototype);
-
 /**
  * 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
@@ -279,27 +265,19 @@ this.ScriptTimeoutError = function(msg) 
 ScriptTimeoutError.prototype = Object.create(WebDriverError.prototype);
 
 this.SessionNotCreatedError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "SessionNotCreatedError";
   this.status = "session not created";
   // should be 33 to match Selenium
   this.code = 71;
-};
+}
 SessionNotCreatedError.prototype = Object.create(WebDriverError.prototype);
 
-this.StaleElementReferenceError = function(msg) {
-  WebDriverError.call(this, msg);
-  this.name = "StaleElementReferenceError";
-  this.status = "stale element reference";
-  this.code = 10;
-};
-StaleElementReferenceError.prototype = Object.create(WebDriverError.prototype);
-
 this.TimeoutError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "TimeoutError";
   this.status = "timeout";
   this.code = 21;
 };
 TimeoutError.prototype = Object.create(WebDriverError.prototype);
 
@@ -321,8 +299,29 @@ UnknownError.prototype = Object.create(W
 
 this.UnsupportedOperationError = function(msg) {
   WebDriverError.call(this, msg);
   this.name = "UnsupportedOperationError";
   this.status = "unsupported operation";
   this.code = 405;
 };
 UnsupportedOperationError.prototype = Object.create(WebDriverError.prototype);
+
+const errorObjs = [
+  this.ElementNotVisibleError,
+  this.FrameSendFailureError,
+  this.FrameSendNotInitializedError,
+  this.IllegalArgumentError,
+  this.InvalidElementStateError,
+  this.JavaScriptError,
+  this.NoAlertOpenError,
+  this.NoSuchElementError,
+  this.NoSuchFrameError,
+  this.NoSuchWindowError,
+  this.ScriptTimeoutError,
+  this.SessionNotCreatedError,
+  this.TimeoutError,
+  this.UnknownCommandError,
+  this.UnknownError,
+  this.UnsupportedOperationError,
+  this.WebDriverError,
+];
+const lookup = new Map(errorObjs.map(err => [new err().code, err]));
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -10,17 +10,16 @@ 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);
@@ -89,17 +88,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
@@ -142,61 +141,30 @@ 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);
@@ -209,27 +177,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", getActiveElementFn);
-  addMessageListenerId("Marionette:clickElement", clickElementFn);
-  addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
-  addMessageListenerId("Marionette:getElementText", getElementTextFn);
-  addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
+  addMessageListenerId("Marionette:getActiveElement", getActiveElement);
+  addMessageListenerId("Marionette:clickElement", clickElement);
+  addMessageListenerId("Marionette:getElementAttribute", getElementAttribute);
+  addMessageListenerId("Marionette:getElementText", getElementText);
+  addMessageListenerId("Marionette:getElementTagName", getElementTagName);
   addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed);
   addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty);
   addMessageListenerId("Marionette:submitElement", submitElement);
-  addMessageListenerId("Marionette:getElementSize", getElementSizeFn);  // deprecated
-  addMessageListenerId("Marionette:getElementRect", getElementRectFn);
-  addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
+  addMessageListenerId("Marionette:getElementSize", getElementSize);
+  addMessageListenerId("Marionette:getElementRect", getElementRect);
+  addMessageListenerId("Marionette:isElementEnabled", isElementEnabled);
   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);
@@ -314,27 +282,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", getActiveElementFn);
-  removeMessageListenerId("Marionette:clickElement", clickElementFn);
-  removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
-  removeMessageListenerId("Marionette:getElementText", getElementTextFn);
-  removeMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
+  removeMessageListenerId("Marionette:getActiveElement", getActiveElement);
+  removeMessageListenerId("Marionette:clickElement", clickElement);
+  removeMessageListenerId("Marionette:getElementAttribute", getElementAttribute);
+  removeMessageListenerId("Marionette:getElementText", getElementText);
+  removeMessageListenerId("Marionette:getElementTagName", getElementTagName);
   removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed);
   removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty);
   removeMessageListenerId("Marionette:submitElement", submitElement);
-  removeMessageListenerId("Marionette:getElementSize", getElementSizeFn); // deprecated
-  removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
-  removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
+  removeMessageListenerId("Marionette:getElementSize", getElementSize);  //deprecated
+  removeMessageListenerId("Marionette:getElementRect", getElementRect);
+  removeMessageListenerId("Marionette:isElementEnabled", isElementEnabled);
   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);
@@ -358,52 +326,50 @@ function deleteSession(msg) {
 
 /*
  * Helper methods
  */
 
 /**
  * Generic method to send a message to the server
  */
-function sendToServer(name, data, objs, id) {
-  if (!data) {
-    data = {}
+function sendToServer(msg, value, command_id) {
+  if (command_id) {
+    value.command_id = command_id;
   }
-  if (id) {
-    data.command_id = id;
-  }
-  sendAsyncMessage(name, data, objs);
+  sendAsyncMessage(msg, value);
 }
 
 /**
  * Send response back to server
  */
 function sendResponse(value, command_id) {
-  sendToServer("Marionette:done", value, null, command_id);
+  sendToServer("Marionette:done", value, command_id);
 }
 
 /**
  * Send ack back to server
  */
 function sendOk(command_id) {
-  sendToServer("Marionette:ok", null, null, command_id);
+  sendToServer("Marionette:ok", {}, 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(err, cmdId) {
-  sendToServer("Marionette:error", null, {error: err}, cmdId);
+function sendError(msg, code, stack, cmdId) {
+  let payload = {message: msg, code: code, stack: stack};
+  sendToServer("Marionette:error", payload, cmdId);
 }
 
 /**
  * Clear test values after completion of test
  */
 function resetValues() {
   sandbox = null;
   curFrame = content;
@@ -487,90 +453,97 @@ function createExecuteContentSandbox(aWi
     });
   }
   else {
     XPCOMUtils.defineLazyGetter(sandbox, 'SpecialPowers', function() {
       return new SpecialPowers(aWindow);
     });
   }
 
-  sandbox.asyncComplete = function(obj, id) {
-    if (id == asyncTestCommandId) {
+  sandbox.asyncComplete = function sandbox_asyncComplete(value, status, stack, commandId) {
+    if (commandId == 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 (error.isError(obj)) {
-        sendError(obj, id);
-      } else {
+      if (status == 0){
         if (Object.keys(_emu_cbs).length) {
           _emu_cbs = {};
-          sendError({message: "Emulator callback still pending when finish() called"}, id);
-        } else {
-          sendResponse({value: elementManager.wrapValue(obj)}, id);
+          sendError("Emulator callback still pending when finish() called",
+                    500, null, commandId);
         }
+        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(), sandbox.asyncTestCommandId);
+      sandbox.asyncComplete(marionette.generate_results(), 0, null, sandbox.asyncTestCommandId);
     } else {
       return marionette.generate_results();
     }
   };
-  sandbox.marionetteScriptFinished = val =>
-      sandbox.asyncComplete(val, sandbox.asyncTestCommandId);
+  sandbox.marionetteScriptFinished = function sandbox_marionetteScriptFinished(value) {
+    return sandbox.asyncComplete(value, 0, null, 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(new ScriptTimeoutError("timed out due to inactivity"), asyncTestCommandId);
+        inactivityTimeoutId = curFrame.setTimeout(function() {
+        sendError('timed out due to inactivity', 28, null, asyncTestCommandId);
       }, msg.json.inactivityTimeout);
    };
 
     setTimer();
-    heartbeatCallback = function() {
+    heartbeatCallback = function resetInactivityTimeout() {
       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(new WebDriverError("Could not create sandbox!"), asyncTestCommandId);
+      sendError("Could not create sandbox!", 500, null, 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);
@@ -580,28 +553,29 @@ 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(new JavaScriptError("Marionette.finish() not called"), asyncTestCommandId);
+        sendError("Marionette.finish() not called", 17, null, 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, asyncTestCommandId);
+      }
+      catch(e) {
+        sendError(e.message, e.code, e.stack, 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);
@@ -611,24 +585,25 @@ 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) {
-    let err = new JavaScriptError(
-        e,
-        "execute_script",
-        msg.json.filename,
-        msg.json.line,
-        script);
-    sendError(err, 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);
   }
 }
 
 /**
  * Sets the test name, used in logging messages.
  */
 function setTestName(msg) {
   marionetteTestName = msg.json.value;
@@ -662,76 +637,77 @@ 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(new ScriptTimeout("timed out due to inactivity"), asyncTestCommandId);
+        sandbox.asyncComplete('timed out due to inactivity', 28, null, asyncTestCommandId);
       }, msg.json.inactivityTimeout);
     };
 
     setTimer();
-    heartbeatCallback = function() {
+    heartbeatCallback = function resetInactivityTimeout() {
       curFrame.clearTimeout(inactivityTimeoutId);
       setTimer();
     };
   }
 
   let script = msg.json.script;
   asyncTestCommandId = msg.json.command_id;
 
   onunload = function() {
-    sendError(new JavaScriptError("unload was called"), asyncTestCommandId);
+    sendError("unload was called", 17, null, asyncTestCommandId);
   };
   curFrame.addEventListener("unload", onunload, false);
 
   if (msg.json.newSandbox || !sandbox) {
     sandbox = createExecuteContentSandbox(curFrame,
                                           msg.json.timeout);
     if (!sandbox) {
-      sendError(new JavaScriptError("Could not create sandbox!"), asyncTestCommandId);
+      sendError("Could not create sandbox!", 17, null, 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(new ScriptTimeoutError("timed out"), asyncTestCommandId);
+    sandbox.asyncComplete('timed out', 28, null, asyncTestCommandId);
   }, msg.json.timeout);
 
   originalOnError = curFrame.onerror;
-  curFrame.onerror = function errHandler(msg, url, line) {
-    sandbox.asyncComplete(new JavaScriptError(msg + "@" + url + ", line " + line), asyncTestCommandId);
+  curFrame.onerror = function errHandler(errMsg, url, line) {
+    sandbox.asyncComplete(errMsg, 17, "@" + url + ", line " + line, asyncTestCommandId);
     curFrame.onerror = originalOnError;
   };
 
   let scriptSrc;
   if (useFinish) {
     if (msg.json.timeout == null || msg.json.timeout == 0) {
-      sendError(new TimeoutError("Please set a timeout"), asyncTestCommandId);
+      sendError("Please set a timeout", 21, null, asyncTestCommandId);
     }
     scriptSrc = script;
   }
   else {
     try {
       sandbox.__marionetteParams = Cu.cloneInto(elementManager.convertWrappedArguments(
         msg.json.args, curFrame), sandbox, { wrapReflectors: true });
-    } catch (e) {
-      sendError(e, asyncTestCommandId);
+    }
+    catch(e) {
+      sendError(e.message, e.code, e.stack, asyncTestCommandId);
       return;
     }
 
     scriptSrc = "__marionetteParams.push(marionetteScriptFinished);" +
                 "let __marionetteFunc = function() { " + script + "};" +
                 "__marionetteFunc.apply(null, __marionetteParams); ";
   }
 
@@ -742,23 +718,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) {
-    let err = new JavaScriptError(
-        e,
-        "execute_async_script",
-        msg.json.filename,
-        msg.json.line,
-        scriptSrc);
-    sandbox.asyncComplete(err, asyncTestCommandId);
+    // 17 = JavascriptException
+    let error = createStackMessage(e,
+                                   "execute_async_script",
+                                   msg.json.filename,
+                                   msg.json.line,
+                                   scriptSrc);
+    sandbox.asyncComplete(error[0], 17, error[1], asyncTestCommandId);
   }
 }
 
 /**
  * This function creates a touch event given a touch type and a touch
  */
 function emitTouchEvent(type, touch) {
   if (!wasInterrupted()) {
@@ -875,34 +851,35 @@ 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(new ElementNotVisibleError("Element is not currently visible and may not be manipulated"), command_id);
+      sendError("Element is not currently visible and may not be manipulated", 11, null, 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(command_id);
-  } catch (e) {
-    sendError(e, command_id);
+    sendOk(msg.json.command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, msg.json.command_id);
   }
 }
 
 /**
  * Check if the element's unavailable accessibility state matches the enabled
  * state
  * @param nsIAccessible object
  * @param Boolean enabled element's enabled state
@@ -977,33 +954,37 @@ 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 = err => sendError(err, command_id);
+  callbacks.onSuccess = (value) => {
+    sendResponse(value, command_id);
+  };
+  callbacks.onError = (message, code, trace) => {
+    sendError(message, code, trace, msg.json.command_id);
+  };
 
   let touchProvider = {};
   touchProvider.createATouch = createATouch;
   touchProvider.emitTouchEvent = emitTouchEvent;
 
   try {
     actions.dispatchActions(
         args,
         touchId,
         curFrame,
         elementManager,
         callbacks,
         touchProvider);
   } catch (e) {
-    sendError(e, command_id);
+    sendError(e.message, e.code, e.stack, 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) {
@@ -1158,18 +1139,19 @@ 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, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, msg.json.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.
  */
@@ -1191,27 +1173,29 @@ 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(new UnknownError("Error loading page"), command_id);
+        sendError("Error loading page", 13, null, 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(new TimeoutError("Error loading page, timed out (checkLoad)"), command_id);
+      sendError("Error loading page, timed out (checkLoad)", 21, null,
+                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
@@ -1231,17 +1215,18 @@ function get(msg) {
         removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
         onDOMContentLoaded = null;
       });
     }
   };
 
   function timerFunc() {
     removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
-    sendError(new TimeoutError("Error loading page, timed out (onDOMContentLoaded)"), msg.json.command_id);
+    sendError("Error loading page, timed out (onDOMContentLoaded)", 21,
+              null, 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;
 }
 
@@ -1316,129 +1301,138 @@ 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 onSuccess = (el, id) => sendResponse({value: el}, id);
-    let onError = (err, id) => sendError(err, id);
+    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); };
     elementManager.find(curFrame, msg.json, msg.json.searchTimeout,
-        false /* all */, onSuccess, onError, command_id);
-  } catch (e) {
-    sendError(e, command_id);
+                        false /* all */, on_success, on_error, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Find elements in the document using requested search strategy
  */
 function findElementsContent(msg) {
   let command_id = msg.json.command_id;
   try {
-    let onSuccess = (els, id) => sendResponse({value: els}, id);
-    let onError = (err, id) => sendError(err, id);
+    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); };
     elementManager.find(curFrame, msg.json, msg.json.searchTimeout,
-        true /* all */, onSuccess, onError, command_id);
-  } catch (e) {
-    sendError(e, command_id);
+                        true /* all */, on_success, on_error, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
- * Find and return the active element on the page.
- *
- * @return {WebElement}
- *     Reference to web element.
+ * Find and return the active element on the page
  */
-function getActiveElement() {
-  let el = curFrame.document.activeElement;
-  return elementManager.addToKnownElements(el);
+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);
 }
 
 /**
- * Send click event to element.
- *
- * @param {WebElement} id
- *     Reference to the web element to click.
+ * Send click event to element
  */
-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");
+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);
   }
-  checkActionableAccessibility(acc);
-  if (utils.isElementEnabled(el)) {
-    utils.synthesizeMouseAtCenter(el, {}, el.ownerDocument.defaultView);
-  } else {
-    throw new InvalidElementStateError("Element is not Enabled");
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
- * 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.
+ * Get a given attribute of an element
  */
-function getElementAttribute(id, name) {
-  let el = elementManager.getKnownElement(id, curFrame);
-  return utils.getElementAttribute(el, name);
+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);
+  }
 }
 
 /**
  * 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(id) {
-  let el = elementManager.getKnownElement(id, curFrame);
-  return utils.getElementText(el);
+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);
+  }
 }
 
 /**
  * Get the tag name of an element.
- *
- * @param {WebElement} id
- *     Reference to web element.
- *
- * @return {string}
- *     Tag name of element.
  */
-function getElementTagName(id) {
-  let el = elementManager.getKnownElement(id, curFrame);
-  return el.tagName.toLowerCase();
+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);
+  }
 }
 
 /**
  * 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, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Return the property of the computed style of an element
  *
  * @param object aRequest
  *               'element' member holds the reference id to
@@ -1447,18 +1441,19 @@ 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, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, 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
   */
@@ -1467,85 +1462,90 @@ 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(new NoSuchElementError("Element is not a form element or in a form"), command_id);
+    }
+    else {
+      sendError("Element is not a form element or in a form", 7, null, command_id);
     }
-  } catch (e) {
-    sendError(e, 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);
   }
 }
 
 /**
- * Get the size of the element.
- *
- * @param {WebElement} id
- *     Web element reference.
- *
- * @return {Object.<string, number>}
- *     The width/height dimensions of th element.
+ * Get the size of the element and return it
  */
-function getElementSize(id) {
-  let el = elementManager.getKnownElement(id, curFrame);
-  let clientRect = el.getBoundingClientRect();
-  return {width: clientRect.width, height: clientRect.height};
+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);
+  }
 }
 
 /**
- * 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.
+ * Check if element is enabled
  */
-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;
+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);
+  }
 }
 
 /**
  * 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, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Send keys to element
  */
 function sendKeysToElement(msg) {
   let command_id = msg.json.command_id;
@@ -1593,18 +1593,19 @@ 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, command_id);
+  }
+  catch (e) {
+    sendError(e.message, e.code, e.stack, command_id);
   }
 }
 
 /**
  * Clear the text of an element
  */
 function clearElement(msg) {
   let command_id = msg.json.command_id;
@@ -1612,34 +1613,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, command_id);
+    sendError(e.message, e.code, e.stack, 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(new UnknownError("Error loading page"), command_id);
+    }
+    else if (curFrame.document.readyState == "interactive" && errorRegex.exec(curFrame.document.baseURI)) {
+      sendError("Error loading page", 13, null, 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
@@ -1669,18 +1670,19 @@ 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, command_id);
+      }
+      catch(e) {
+        sendError(e.message, e.code, e.stack, 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;
@@ -1728,19 +1730,18 @@ 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(new NoSuchFrameError("Unable to locate frame: " + (msg.json.id || msg.json.element)), command_id);
+    sendError("Unable to locate frame: " + (msg.json.id || msg.json.element), 8, null, 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'];
@@ -1771,39 +1772,40 @@ 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(new InvalidCookieDomainError("You may only set cookies for the current domain"), msg.json.command_id);
+      sendError("You may only set cookies for the current domain", 24, null, 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(new UnableToSetCookie("You may only set cookies on html documents"), msg.json.command_id);
+    sendError('You may only set cookies on html documents', 25, null, msg.json.command_id);
   }
 
   let added = sendSyncMessage("Marionette:addCookie", {value: cookie});
   if (added[0] !== true) {
-    sendError(new UnknownError("Error setting cookie"), msg.json.command_id);
+    sendError("Error setting cookie", 13, null, msg.json.command_id);
     return;
   }
   sendOk(msg.json.command_id);
 }
 
 /**
  * Get all cookies for the current domain.
  */
@@ -1834,34 +1836,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(new UnknownError("Could not delete cookie: " + msg.json.name), msg.json.command_id);
+        sendError("Could not delete cookie: " + msg.json.name, 13, null, 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(new UnknownError("Could not delete cookie: " + JSON.stringify(cookie)), msg.json.command_id);
+      sendError("Could not delete cookie: " + JSON.stringify(cookie), 13, null, msg.json.command_id);
       return;
     }
   }
   sendOk(msg.json.command_id);
 }
 
 /**
  * Get all the visible cookies from a location
@@ -1905,18 +1907,19 @@ 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, -1);
+  }
+  catch(e) {
+    sendError(e.message, e.code, e.stack, -1);
     return;
   }
 }
 
 function importScript(msg) {
   let command_id = msg.json.command_id;
   let file;
   if (importedScripts.exists()) {
--- a/testing/marionette/sendkeys.js
+++ b/testing/marionette/sendkeys.js
@@ -12,21 +12,18 @@
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 
 let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
 let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
-    .getService(Ci.mozIJSSubScriptLoader);
+               .getService(Ci.mozIJSSubScriptLoader);
 
 let utils = {};
 loader.loadSubScript("chrome://marionette/content/EventUtils.js", utils);
 loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", utils);
 
 let keyModifierNames = {
     "VK_SHIFT": 'shiftKey',
     "VK_CONTROL": 'ctrlKey',
@@ -136,12 +133,13 @@ function sendKeysToElement (document, el
       metaKey: false
     };
     let value = keysToSend.join("");
     for (var i = 0; i < value.length; i++) {
       var c = value.charAt(i);
       sendSingleKey(c, modifiers, document);
     }
     successCallback(command_id);
-  } else {
-    errorCallback(new ElementNotVisibleError("Element is not visible"), command_id);
+  }
+  else {
+    errorCallback("Element is not visible", 11, null, command_id);
   }
 };