Bug 1107706: Part 1: Change context from strings to enum
authorAndreas Tolfsen <ato@mozilla.com>
Wed, 25 Feb 2015 21:11:51 +0000
changeset 266306 31df2186195a474ae202f33a6bfef3167a0190dc
parent 266305 0db3b8dc05e2e8b2ad372a4b7bbe23fa85827b99
child 266307 42f14f453f1ffa7cb4590f7f0b7c16fb43c97740
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1107706
milestone39.0a1
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
Bug 1107706: Part 1: Change context from strings to enum
testing/marionette/marionette-sendkeys.js
testing/marionette/marionette-server.js
--- a/testing/marionette/marionette-sendkeys.js
+++ b/testing/marionette/marionette-sendkeys.js
@@ -118,18 +118,18 @@ function sendSingleKey (keyToSend, modif
     let modName = keyModifierNames[keyCode];
     modifiers[modName] = !modifiers[modName];
   } else if (modifiers.shiftKey) {
     keyCode = keyCode.toUpperCase();
   }
   utils.synthesizeKey(keyCode, modifiers, document);
 }
 
-function sendKeysToElement (document, element, keysToSend, successCallback, errorCallback, command_id, context) {
-  if (context == "chrome" || checkVisible(element)) {
+function sendKeysToElement (document, element, keysToSend, successCallback, errorCallback, command_id, ignoreVisibility) {
+  if (ignoreVisibility || checkVisible(element)) {
     element.focus();
     let modifiers = {
       shiftKey: false,
       ctrlKey: false,
       altKey: false,
       metaKey: false
     };
     let value = keysToSend.join("");
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -90,16 +90,28 @@ Services.obs.addObserver(function() {
 
 // This is used on desktop to prevent newSession from returning before a page
 // load initiated by the Firefox command line has completed.
 let delayedBrowserStarted = false;
 Services.obs.addObserver(function () {
   delayedBrowserStarted = true;
 }, BROWSER_STARTUP_FINISHED, false);
 
+const Context = {
+  CHROME: "chrome",
+  CONTENT: "content",
+};
+
+Context.fromString = function(s) {
+  s = s.toUpperCase();
+  if (s in this)
+    return this[s];
+  return null;
+};
+
 /*
  * Custom exceptions
  */
 function FrameSendNotInitializedError(frame) {
   this.code = 54;
   this.frame = frame;
   this.message = "Error sending message to frame (NS_ERROR_NOT_INITIALIZED)";
   this.toString = function() {
@@ -137,30 +149,32 @@ function MarionetteServerConnection(aPre
   this.actorID = "0";
   this.sessionId = null;
 
   this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
                              .getService(Ci.nsIMessageBroadcaster);
   this.messageManager = this.globalMessageManager;
   this.browsers = {}; //holds list of BrowserObjs
   this.curBrowser = null; // points to current browser
-  this.context = "content";
+  this.context = Context.CONTENT;
   this.scriptTimeout = null;
   this.searchTimeout = null;
   this.pageTimeout = null;
   this.timer = null;
   this.inactivityTimer = null;
   this.heartbeatCallback = function () {}; // called by simpletest methods
   this.marionetteLog = new MarionetteLogObj();
   this.command_id = null;
   this.mainFrame = null; //topmost chrome frame
   this.curFrame = null; // chrome iframe that currently has focus
   this.mainContentFrameId = null;
   this.importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
-  this.importedScriptHashes = {"chrome" : [], "content": []};
+  this.importedScriptHashes = {};
+  this.importedScriptHashes[Context.CONTENT] = [];
+  this.importedScriptHashes[Context.CHROME] = [];
   this.currentFrameElement = null;
   this.testName = null;
   this.mozBrowserClose = null;
   this.enabled_security_pref = false;
   this.sandbox = null;
   this.oopFrameId = null; // frame ID of current remote frame, used for mozbrowserclose events
   this.sessionCapabilities = {
     // Mandated capabilities
@@ -190,17 +204,16 @@ function MarionetteServerConnection(aPre
 
   this.observing = null;
   this._browserIds = new WeakMap();
   this.quitFlags = null;
   this.actions = new ActionChain(utils);
 }
 
 MarionetteServerConnection.prototype = {
-
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   /**
    * Debugger transport callbacks:
    */
   onPacket: function MSC_onPacket(aPacket) {
@@ -414,17 +427,17 @@ MarionetteServerConnection.prototype = {
    * Gets the current active window
    *
    * @return nsIDOMWindow
    */
   getCurrentWindow: function MDA_getCurrentWindow() {
     let type = null;
     if (this.curFrame == null) {
       if (this.curBrowser == null) {
-        if (this.context == "content") {
+        if (this.context == Context.CONTENT) {
           type = 'navigator:browser';
         }
         return Services.wm.getMostRecentWindow(type);
       }
       else {
         return this.curBrowser.window;
       }
     }
@@ -435,17 +448,17 @@ MarionetteServerConnection.prototype = {
 
   /**
    * Gets the the window enumerator
    *
    * @return nsISimpleEnumerator
    */
   getWinEnumerator: function MDA_getWinEnumerator() {
     let type = null;
-    if (appName != "B2G" && this.context == "content") {
+    if (appName != "B2G" && this.context == Context.CONTENT) {
       type = 'navigator:browser';
     }
     return Services.wm.getEnumerator(type);
   },
 
   /**
   */
   addFrameCloseListener: function MDA_addFrameCloseListener(action) {
@@ -809,22 +822,22 @@ MarionetteServerConnection.prototype = {
   /**
    * Sets the context of the subsequent commands to be either 'chrome' or 'content'
    *
    * @param object aRequest
    *        'value' member holds the name of the context to be switched to
    */
   setContext: function MDA_setContext(aRequest) {
     this.command_id = this.getCommandId();
-    let context = aRequest.parameters.value;
-    if (context != "content" && context != "chrome") {
+    let val = aRequest.parameters.value;
+    let ctx = Context.fromString(val);
+    if (ctx === null) {
       this.sendError("invalid context", 500, null, this.command_id);
-    }
-    else {
-      this.context = context;
+    } else {
+      this.context = ctx;
       this.sendOk(this.command_id);
     }
   },
 
   /**
    * Gets the context of the server, either 'chrome' or 'content'.
    */
   getContext: function MDA_getContext() {
@@ -951,17 +964,17 @@ MarionetteServerConnection.prototype = {
     let command_id = this.command_id = this.getCommandId();
     let script;
     let newSandbox = aRequest.parameters.newSandbox;
     if (newSandbox == undefined) {
       //if client does not send a value in newSandbox,
       //then they expect the same behaviour as webdriver
       newSandbox = true;
     }
-    if (this.context == "content") {
+    if (this.context == Context.CONTENT) {
       this.sendAsync("executeScript",
                      {
                        script: aRequest.parameters.script,
                        args: aRequest.parameters.args,
                        newSandbox: newSandbox,
                        timeout: timeout,
                        specialPowers: aRequest.parameters.specialPowers,
                        filename: aRequest.parameters.filename,
@@ -1071,38 +1084,42 @@ MarionetteServerConnection.prototype = {
     let command_id = this.command_id = this.getCommandId();
 
     //all pure JS scripts will need to call Marionette.finish() to complete the test.
     if (aRequest.newSandbox == undefined) {
       //if client does not send a value in newSandbox,
       //then they expect the same behaviour as webdriver
       aRequest.newSandbox = true;
     }
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       if (aRequest.parameters.async) {
         this.executeWithCallback(aRequest, aRequest.parameters.async);
       }
       else {
         this.execute(aRequest, true);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("executeJSScript",
                      {
                        script: aRequest.parameters.script,
                        args: aRequest.parameters.args,
                        newSandbox: aRequest.parameters.newSandbox,
                        async: aRequest.parameters.async,
                        timeout: timeout,
                        inactivityTimeout: aRequest.parameters.inactivityTimeout,
                        specialPowers: aRequest.parameters.specialPowers,
                        filename: aRequest.parameters.filename,
                        line: aRequest.parameters.line,
                      },
                      command_id);
+      break;
    }
   },
 
   /**
    * This function is used by executeAsync and executeJSScript to execute a script
    * in a sandbox.
    *
    * For executeJSScript, it will return a message only when the finish() method is called.
@@ -1123,17 +1140,17 @@ MarionetteServerConnection.prototype = {
     let script;
     let newSandbox = aRequest.parameters.newSandbox;
     if (newSandbox == undefined) {
       //if client does not send a value in newSandbox,
       //then they expect the same behaviour as webdriver
       newSandbox = true;
     }
 
-    if (this.context == "content") {
+    if (this.context == Context.CONTENT) {
       this.sendAsync("executeAsyncScript",
                      {
                        script: aRequest.parameters.script,
                        args: aRequest.parameters.args,
                        id: this.command_id,
                        newSandbox: newSandbox,
                        timeout: timeout,
                        inactivityTimeout: inactivityTimeout,
@@ -1290,25 +1307,26 @@ MarionetteServerConnection.prototype = {
    * complete.  This does not include FORM-based authentication.
    *
    * @param object aRequest where <code>url</code> property holds the
    *        URL to navigate to
    */
   get: function MDA_get(aRequest) {
     let command_id = this.command_id = this.getCommandId();
 
-    if (this.context != "chrome") {
+    if (this.context == Context.CONTENT) {
       // If a remoteness update interrupts our page load, this will never return
       // We need to re-issue this request to correctly poll for readyState and
       // send errors.
       this.curBrowser.pendingCommands.push(() => {
         aRequest.parameters.command_id = command_id;
         this.messageManager.broadcastAsyncMessage(
           "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
           aRequest.parameters);
+        return;
       });
       aRequest.command_id = command_id;
       aRequest.parameters.pageTimeout = this.pageTimeout;
       this.sendAsync("get", aRequest.parameters, command_id);
       return;
     }
 
     // At least on desktop, navigating in chrome scope does not
@@ -1354,62 +1372,72 @@ MarionetteServerConnection.prototype = {
    * document.location.href.
    *
    * When in the context of the chrome, this returns the canonical URL
    * of the current resource.
    */
   getCurrentUrl: function MDA_getCurrentUrl() {
     let isB2G = appName == "B2G";
     this.command_id = this.getCommandId();
-    if (this.context === "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       this.sendResponse(this.getCurrentWindow().location.href, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getCurrentUrl", {isB2G: isB2G}, this.command_id);
+      break;
     }
   },
 
   /**
    * Gets the current title of the window
    */
   getTitle: function MDA_getTitle() {
     this.command_id = this.getCommandId();
-    if (this.context == "chrome"){
+    switch (this.context) {
+    case Context.CHROME:
       var curWindow = this.getCurrentWindow();
       var title = curWindow.document.documentElement.getAttribute('title');
       this.sendResponse(title, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getTitle", {}, this.command_id);
+      break;
     }
   },
 
   /**
    * Gets the current type of the window
    */
   getWindowType: function MDA_getWindowType() {
     this.command_id = this.getCommandId();
-      var curWindow = this.getCurrentWindow();
-      var type = curWindow.document.documentElement.getAttribute('windowtype');
-      this.sendResponse(type, this.command_id);
+    let win = this.getCurrentWindow();
+    let typ = win.document.documentElement.getAttribute("windowtype");
+    this.sendResponse(typ, this.command_id);
   },
 
   /**
    * Gets the page source of the content document
    */
   getPageSource: function MDA_getPageSource(){
     this.command_id = this.getCommandId();
-    if (this.context == "chrome"){
-      let curWindow = this.getCurrentWindow();
-      let XMLSerializer = curWindow.XMLSerializer;
-      let pageSource = new XMLSerializer().serializeToString(curWindow.document);
+    switch (this.context) {
+    case Context.CHROME:
+      let win = this.getCurrentWindow();
+      let s = new win.XMLSerializer();
+      let pageSource = s.serializeToString(win.document);
       this.sendResponse(pageSource, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getPageSource", {}, this.command_id);
+      break;
     }
   },
 
   /**
    * Go back in history
    */
   goBack: function MDA_goBack() {
     this.command_id = this.getCommandId();
@@ -1662,27 +1690,30 @@ MarionetteServerConnection.prototype = {
     }
     this.sendError("Unable to locate window " + aRequest.parameters.name, 23, null,
                    command_id);
   },
 
   getActiveFrame: function MDA_getActiveFrame() {
     this.command_id = this.getCommandId();
 
-    if (this.context == "chrome") {
+    switch (this.context) {
+    case Context.CHROME:
       if (this.curFrame) {
         let frameUid = this.curBrowser.elementManager.addToKnownElements(this.curFrame.frameElement);
         this.sendResponse(frameUid, this.command_id);
       } else {
         // no current frame, we're at toplevel
         this.sendResponse(null, this.command_id);
       }
-    } else {
-      // not chrome
+      break;
+
+    case Context.CONTENT:
       this.sendResponse(this.currentFrameElement, this.command_id);
+      break;
     }
   },
 
   /**
    * Switch to a given frame within the current window
    *
    * @param object aRequest
    *        'element' is the element to switch to
@@ -1703,17 +1734,17 @@ MarionetteServerConnection.prototype = {
       }
       else if (curWindow.document.readyState == "interactive" && errorRegex.exec(curWindow.document.baseURI)) {
         this.sendError("Error loading page", 13, null, command_id);
         return;
       }
 
       checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
     }
-    if (this.context == "chrome") {
+    if (this.context == Context.CHROME) {
       let foundFrame = null;
       if ((aRequest.parameters.id == null) && (aRequest.parameters.element == null)) {
         this.curFrame = null;
         if (aRequest.parameters.focus) {
           this.mainFrame.focus();
         }
         checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
         return;
@@ -1853,42 +1884,42 @@ MarionetteServerConnection.prototype = {
    * @param object aRequest
             'element' represents the ID of the element to single tap on
    */
   singleTap: function MDA_singleTap(aRequest) {
     this.command_id = this.getCommandId();
     let serId = aRequest.parameters.id;
     let x = aRequest.parameters.x;
     let y = aRequest.parameters.y;
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       this.sendError("Command 'singleTap' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.addFrameCloseListener("tap");
-      this.sendAsync("singleTap",
-                     {
-                       id: serId,
-                       corx: x,
-                       cory: y
-                     },
-                     this.command_id);
+      this.sendAsync("singleTap", {id: serId, corx: x, cory: y}, this.command_id);
+      break;
     }
   },
 
   /**
    * actionChain
    *
    * @param object aRequest
    *        'value' represents a nested array: inner array represents each event; outer array represents collection of events
    */
   actionChain: function MDA_actionChain(aRequest) {
     let command_id = this.command_id = this.getCommandId();
     let chain = aRequest.parameters.chain;
     let nextId = aRequest.parameters.nextId;
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       if (appName != 'Firefox') {
         // Be conservative until this has a use case and is established to work as
         // expected on b2g/fennec.
         this.sendError("Command 'actionChain' is not available in chrome context",
                        500, null, this.command_id);
       }
 
       let callbacks = {};
@@ -1897,62 +1928,70 @@ MarionetteServerConnection.prototype = {
       };
       callbacks.onError = (message, code, trace) => {
         this.sendError(message, code, trace, command_id);
       };
 
       let currWin = this.getCurrentWindow();
       let elementManager = this.curBrowser.elementManager;
       this.actions.dispatchActions(chain, nextId, currWin, elementManager, callbacks);
-    } else {
+      break;
+
+    case Context.CONTENT:
       this.addFrameCloseListener("action chain");
       this.sendAsync("actionChain",
                      {
                        chain: chain,
                        nextId: nextId
                      },
                      command_id);
+      break;
     }
   },
 
   /**
    * multiAction
    *
    * @param object aRequest
    *        'value' represents a nested array: inner array represents each event;
    *        middle array represents collection of events for each finger
    *        outer array represents all the fingers
    */
 
   multiAction: function MDA_multiAction(aRequest) {
     this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-       this.sendError("Command 'multiAction' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
+    switch (this.context) {
+    case Context.CHROME:
+      this.sendError("Command 'multiAction' is not available in chrome context", 500, null, this.command_id);
+      break;
+
+    case Context.CONTENT:
       this.addFrameCloseListener("multi action chain");
       this.sendAsync("multiAction",
                      {
                        value: aRequest.parameters.value,
                        maxlen: aRequest.parameters.max_length
                      },
                      this.command_id);
+     break;
    }
  },
 
   /**
    * Find an element using the indicated search strategy.
    *
    * @param object aRequest
    *        'using' member indicates which search method to use
    *        'value' member is the value the client is looking for
    */
   findElement: function MDA_findElement(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       let id;
       try {
         let on_success = this.sendResponse.bind(this);
         let on_error = this.sendError.bind(this);
         id = this.curBrowser.elementManager.find(
                               this.getCurrentWindow(),
                               aRequest.parameters,
                               this.searchTimeout,
@@ -1960,26 +1999,28 @@ MarionetteServerConnection.prototype = {
                               on_error,
                               false,
                               command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
         return;
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("findElementContent",
                      {
                        value: aRequest.parameters.value,
                        using: aRequest.parameters.using,
                        element: aRequest.parameters.element,
                        searchTimeout: this.searchTimeout
                      },
                      command_id);
+      break;
     }
   },
 
   /**
    * Find element using the indicated search strategy
    * starting from a known element. Used for WebDriver Compatibility only.
    * @param  {object} aRequest
    *         'using' member indicates which search method to use
@@ -2002,43 +2043,47 @@ MarionetteServerConnection.prototype = {
    * Find elements using the indicated search strategy.
    *
    * @param object aRequest
    *        'using' member indicates which search method to use
    *        'value' member is the value the client is looking for
    */
   findElements: function MDA_findElements(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       let id;
       try {
         let on_success = this.sendResponse.bind(this);
         let on_error = this.sendError.bind(this);
         id = this.curBrowser.elementManager.find(this.getCurrentWindow(),
                                                  aRequest.parameters,
                                                  this.searchTimeout,
                                                  on_success,
                                                  on_error,
                                                  true,
                                                  command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
         return;
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("findElementsContent",
                      {
                        value: aRequest.parameters.value,
                        using: aRequest.parameters.using,
                        element: aRequest.parameters.element,
                        searchTimeout: this.searchTimeout
                      },
                      command_id);
+      break;
     }
   },
 
   /**
    * Find elements using the indicated search strategy
    * starting from a known element. Used for WebDriver Compatibility only.
    * @param  {object} aRequest
    *         'using' member indicates which search method to use
@@ -2069,150 +2114,170 @@ MarionetteServerConnection.prototype = {
    * Send click event to element
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be clicked
    */
   clickElement: function MDA_clickElementent(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         //NOTE: click atom fails, fall back to click() action
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         el.click();
         this.sendOk(command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      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");
       this.sendAsync("clickElement",
                      { id: aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Get a given attribute of an element
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be inspected
    *        'name' member holds the name of the attribute to retrieve
    */
   getElementAttribute: function MDA_getElementAttribute(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         this.sendResponse(utils.getElementAttribute(el, aRequest.parameters.name),
                           command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getElementAttribute",
                      {
                        id: aRequest.parameters.id,
                        name: aRequest.parameters.name
                      },
                      command_id);
+      break;
     }
   },
 
   /**
    * Get the text of an element, if any. Includes the text of all child elements.
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be inspected
    */
   getElementText: function MDA_getElementText(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      //Note: for chrome, we look at text nodes, and any node with a "label" field
+
+    switch (this.context) {
+    case Context.CHROME:
+      // Note: for chrome, we look at text nodes, and any node with a "label" field
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         let lines = [];
         this.getVisibleText(el, lines);
         lines = lines.join("\n");
         this.sendResponse(lines, command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getElementText",
                      { id: aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Get the tag name of the element.
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be inspected
    */
   getElementTagName: function MDA_getElementTagName(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Content.CHROME:
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         this.sendResponse(el.tagName.toLowerCase(), command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getElementTagName",
                      { id: aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Check if element is displayed
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be checked
    */
   isElementDisplayed: function MDA_isElementDisplayed(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         this.sendResponse(utils.isElementDisplayed(el), command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("isElementDisplayed",
                      { id:aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Return the property of the computed style of an element
    *
    * @param object aRequest
    *               'id' member holds the reference id to
@@ -2241,58 +2306,69 @@ MarionetteServerConnection.prototype = {
   /**
    * Submit a form on a content page by either using form or element in a form
    * @param object aRequest
    *               'id' member holds the reference id to
    *               the element that will be checked
   */
   submitElement: function MDA_submitElement(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       this.sendError("Command 'submitElement' is not available in chrome context", 500, null, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("submitElement", {id: aRequest.parameters.id}, command_id);
+      break;
     }
   },
 
   /**
    * Check if element is enabled
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be checked
    */
   isElementEnabled: function(aRequest) {
     let command_id = this.command_id = this.getCommandId();
     let id = aRequest.parameters.id;
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         // Selenium atom doesn't quite work here
         let win = this.getCurrentWindow();
         let el = this.curBrowser.elementManager.getKnownElement(id, win);
         this.sendResponse(!!!el.disabled, command_id);
       } catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    } else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("isElementEnabled", {id: id}, command_id);
+      break;
     }
   },
 
   /**
    * Check if element is selected
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be checked
    */
   isElementSelected: function MDA_isElementSelected(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         //Selenium atom doesn't quite work here
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         if (el.checked != undefined) {
           this.sendResponse(!!el.checked, command_id);
         }
         else if (el.selected != undefined) {
@@ -2300,93 +2376,107 @@ MarionetteServerConnection.prototype = {
         }
         else {
           this.sendResponse(true, command_id);
         }
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("isElementSelected",
                      { id:aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   getElementSize: function MDA_getElementSize(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         let clientRect = el.getBoundingClientRect();
         this.sendResponse({width: clientRect.width, height: clientRect.height},
                           command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getElementSize",
                      { id:aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   getElementRect: function MDA_getElementRect(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         let clientRect = el.getBoundingClientRect();
         this.sendResponse({x: clientRect.x + this.getCurrentWindow().pageXOffset,
                            y: clientRect.y + this.getCurrentWindow().pageYOffset,
                            width: clientRect.width, height: clientRect.height},
                            command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("getElementRect",
                      { id:aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Send key presses to element after focusing on it
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be checked
    *        'value' member holds the value to send to the element
    */
   sendKeysToElement: function MDA_sendKeysToElement(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       let currentWindow = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(
         aRequest.parameters.id, currentWindow);
       utils.sendKeysToElement(currentWindow, el, aRequest.parameters.value,
                               this.sendOk.bind(this), this.sendError.bind(this),
-                              command_id, this.context);
-    }
-    else {
+                              command_id, true /* ignore visibility check */);
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("sendKeysToElement",
                      {
                        id:aRequest.parameters.id,
                        value: aRequest.parameters.value
                      },
                      command_id);
+      break;
     }
   },
 
   /**
    * Sets the test name
    *
    * The test name is used in logging messages.
    */
@@ -2402,37 +2492,41 @@ MarionetteServerConnection.prototype = {
    * Clear the text of an element
    *
    * @param object aRequest
    *        'id' member holds the reference id to
    *        the element that will be cleared
    */
   clearElement: function MDA_clearElement(aRequest) {
     let command_id = this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
-      //the selenium atom doesn't work here
+
+    switch (this.context) {
+    case Context.CHROME:
+      // The selenium atom doesn't work here
       try {
         let el = this.curBrowser.elementManager.getKnownElement(
             aRequest.parameters.id, this.getCurrentWindow());
         if (el.nodeName == "textbox") {
           el.value = "";
         }
         else if (el.nodeName == "checkbox") {
           el.checked = false;
         }
         this.sendOk(command_id);
       }
       catch (e) {
         this.sendError(e.message, e.code, e.stack, command_id);
       }
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("clearElement",
                      { id:aRequest.parameters.id },
                      command_id);
+      break;
     }
   },
 
   /**
    * Get an element's location on the page.
    *
    * The returned point will contain the x and y coordinates of the
    * top left-hand corner of the given element.  The point (0,0)
@@ -2728,17 +2822,17 @@ MarionetteServerConnection.prototype = {
       }
       this._emu_cbs[this._emu_cb_id] = callback;
     }
     this.sendToClient({emulator_shell: args, id: this._emu_cb_id}, -1);
     this._emu_cb_id += 1;
   },
 
   emulatorCmdResult: function emulatorCmdResult(message) {
-    if (this.context != "chrome") {
+    if (this.context == Context.CONTENT) {
       this.sendAsync("emulatorCmdResult", message, -1);
       return;
     }
 
     if (!this._emu_cbs) {
       return;
     }
 
@@ -2770,49 +2864,56 @@ MarionetteServerConnection.prototype = {
     ch.update(data, data.length);
     let hash = ch.finish(true);
     if (this.importedScriptHashes[this.context].indexOf(hash) > -1) {
         //we have already imported this script
         this.sendOk(command_id);
         return;
     }
     this.importedScriptHashes[this.context].push(hash);
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       let file;
       if (this.importedScripts.exists()) {
         file = FileUtils.openFileOutputStream(this.importedScripts,
             FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY);
       }
       else {
         //Note: The permission bits here don't actually get set (bug 804563)
         this.importedScripts.createUnique(
             Components.interfaces.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
         file = FileUtils.openFileOutputStream(this.importedScripts,
             FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
         this.importedScripts.permissions = parseInt("0666", 8); //actually set permissions
       }
       file.write(aRequest.parameters.script, aRequest.parameters.script.length);
       file.close();
       this.sendOk(command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("importScript",
                      { script: aRequest.parameters.script },
                      command_id);
+      break;
     }
   },
 
   clearImportedScripts: function MDA_clearImportedScripts(aRequest) {
     let command_id = this.command_id = this.getCommandId();
     try {
-      if (this.context == "chrome") {
+      switch (this.context) {
+      case Context.CHROME:
         this.deleteFile('marionetteChromeScripts');
-      }
-      else {
+        break;
+
+      case Context.CONTENT:
         this.deleteFile('marionetteContentScripts');
+        break;
       }
     }
     catch (e) {
       this.sendError("Could not clear imported scripts", 500, e.name + ": " + e.message, command_id);
       return;
     }
     this.sendOk(command_id);
   },
@@ -2832,17 +2933,19 @@ MarionetteServerConnection.prototype = {
    * entire viewport.
    *
    * @param {string} [id] Reference to a web element.
    * @param {string} [highlights] List of web elements to highlight.
    * @return {string} PNG image encoded as base 64 string.
    */
   takeScreenshot: function MDA_takeScreenshot(aRequest) {
     this.command_id = this.getCommandId();
-    if (this.context == "chrome") {
+
+    switch (this.context) {
+    case Context.CHROME:
       var win = this.getCurrentWindow();
       var canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
       var doc;
       if (appName == "B2G") {
         doc = win.document.body;
       } else {
         doc = win.document.getElementsByTagName('window')[0];
       }
@@ -2870,23 +2973,25 @@ MarionetteServerConnection.prototype = {
           context.DRAWWINDOW_DRAW_VIEW |
           context.DRAWWINDOW_USE_WIDGET_LAYERS;
       }
       context.scale(scale, scale);
       context.drawWindow(win, 0, 0, width, height, "rgb(255,255,255)", flags);
       var dataUrl = canvas.toDataURL("image/png", "");
       var data = dataUrl.substring(dataUrl.indexOf(",") + 1);
       this.sendResponse(data, this.command_id);
-    }
-    else {
+      break;
+
+    case Context.CONTENT:
       this.sendAsync("takeScreenshot",
                    {id: aRequest.parameters.id,
                     highlights: aRequest.parameters.highlights,
                     full: aRequest.parameters.full},
                    this.command_id);
+      break;
     }
   },
 
   /**
    * Get the current browser orientation.
    *
    * Will return one of the valid primary orientation values
    * portrait-primary, landscape-primary, portrait-secondary, or