Bug 1322383 - Add missing checks for valid window r=ato+446296
☠☠ backed out by b43926a87603 ☠ ☠
authorHenrik Skupin <mail@hskupin.info>
Fri, 03 Feb 2017 17:49:38 +0100
changeset 394337 74b0c928a23e261b8976fbbdbcf8e1ab49c57a7c
parent 394190 e1b741382dc0262efb123c0188037264ae887d48
child 394338 890130185456c469b38b7ef0973a8b0c5b07bb86
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1322383, 446296
milestone54.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 1322383 - Add missing checks for valid window r=ato+446296 MozReview-Commit-ID: Ad67SPx8vBx
testing/marionette/assert.js
testing/marionette/driver.js
testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_management.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_status_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_status_content.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py
testing/marionette/harness/marionette_harness/tests/unit/test_window_type_chrome.py
testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
testing/marionette/listener.js
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -113,16 +113,35 @@ assert.content = function (context, msg 
  *     If the current browser is not B2G or Fennec.
  */
 assert.mobile = function (msg = "") {
   msg = msg || "Only supported in Fennec or B2G";
   assert.that(() => isFennec() || isB2G(), msg, UnsupportedOperationError)();
 };
 
 /**
+ * Asserts that |win| is open.
+ *
+ * @param {ChromeWindow} win
+ *     Chrome window to test.
+ * @param {string=} msg
+ *     Custom error message.
+ *
+ * @return {ChromeWindow}
+ *     |win| is returned unaltered.
+ *
+ * @throws {NoSuchWindowError}
+ *     If |win| has been closed.
+ */
+assert.window = function (win, msg = "") {
+  msg = msg || "Unable to locate window";
+  return assert.that(w => w && w.document.defaultView, msg, NoSuchWindowError)(win);
+}
+
+/**
  * Asserts that |obj| is defined.
  *
  * @param {?} obj
  *     Value to test.
  * @param {string=} msg
  *     Custom error message.
  *
  * @return {?}
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -307,32 +307,44 @@ GeckoDriver.prototype.sendTargettedAsync
         throw new WebDriverError(e);
     }
   }
 };
 
 /**
  * Gets the current active window.
  *
+ * @param {Context=} forcedContext
+ *     Optional name of the context to use for the checks.
+ *     Defaults to the current context.
+ *
  * @return {nsIDOMWindow}
  */
-GeckoDriver.prototype.getCurrentWindow = function() {
-  let typ = null;
+GeckoDriver.prototype.getCurrentWindow = function (forcedContext = undefined) {
+  let context = typeof forcedContext == "undefined" ? this.context : forcedContext;
+  let win = null;
+
   if (this.curFrame === null) {
     if (this.curBrowser === null) {
-      if (this.context == Context.CONTENT) {
-        typ = "navigator:browser";
+      let typ = (context === Context.CONTENT) ? "navigator:browser" : null;
+      win = Services.wm.getMostRecentWindow(typ);
+    } else {
+      if (context === Context.CHROME) {
+        win = this.curBrowser.window;
+      } else {
+        if (this.curBrowser.tab && browser.getBrowserForTab(this.curBrowser.tab)) {
+          win = this.curBrowser.window;
+        }
       }
-      return Services.wm.getMostRecentWindow(typ);
-    } else {
-      return this.curBrowser.window;
     }
   } else {
-    return this.curFrame;
+    win = this.curFrame;
   }
+
+  return win;
 };
 
 GeckoDriver.prototype.addFrameCloseListener = function (action) {
   let win = this.getCurrentWindow();
   this.mozBrowserClose = e => {
     if (e.target.id == this.oopFrameId) {
       win.removeEventListener("mozbrowserclose", this.mozBrowserClose, true);
       this.switchToGlobalMessageManager();
@@ -761,16 +773,18 @@ GeckoDriver.prototype.getContext = funct
  *
  * @throws ScriptTimeoutError
  *     If the script was interrupted due to reaching the {@code
  *     scriptTimeout} or default timeout.
  * @throws JavaScriptError
  *     If an Error was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeScript = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let {script, args, scriptTimeout} = cmd.parameters;
   scriptTimeout = scriptTimeout || this.timeouts.script;
 
   let opts = {
     sandboxName: cmd.parameters.sandbox,
     newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
         cmd.parameters.newSandbox,
     filename: cmd.parameters.filename,
@@ -834,16 +848,18 @@ GeckoDriver.prototype.executeScript = fu
  *
  * @throws ScriptTimeoutError
  *     If the script was interrupted due to reaching the {@code
  *     scriptTimeout} or default timeout.
  * @throws JavaScriptError
  *     If an Error was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeAsyncScript = function* (cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let {script, args, scriptTimeout} = cmd.parameters;
   scriptTimeout = scriptTimeout || this.timeouts.script;
 
   let opts = {
     sandboxName: cmd.parameters.sandbox,
     newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
         cmd.parameters.newSandbox,
     filename: cmd.parameters.filename,
@@ -884,28 +900,29 @@ GeckoDriver.prototype.execute_ = functio
 
 /**
  * Execute pure JavaScript.  Used to execute simpletest harness tests,
  * which are like mochitests only injected using Marionette.
  *
  * Scripts are expected to call the {@code finish} global when done.
  */
 GeckoDriver.prototype.executeJSScript = function* (cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {script, args, scriptTimeout} = cmd.parameters;
   scriptTimeout = scriptTimeout || this.timeouts.script;
 
   let opts = {
     filename: cmd.parameters.filename,
     line: cmd.parameters.line,
     async: cmd.parameters.async,
   };
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let wargs = element.fromJson(args, this.curBrowser.seenEls, win);
       let harness = new simpletest.Harness(
           win,
           Context.CHROME,
           this.marionetteLog,
           scriptTimeout,
           function() {},
           this.testName);
@@ -944,16 +961,17 @@ GeckoDriver.prototype.executeJSScript = 
  * the supplied URL and wait until document.readyState equals "complete"
  * or the page timeout duration has elapsed.
  *
  * @param {string} url
  *     URL to navigate to.
  */
 GeckoDriver.prototype.get = function*(cmd, resp) {
   assert.content(this.context);
+  assert.window(this.getCurrentWindow());
 
   let url = cmd.parameters.url;
 
   let get = this.listener.get({url: url, pageTimeout: this.timeouts.pageLoad});
   // TODO(ato): Bug 1242595
   let id = this.listener.activeMessageId;
 
   // If a remoteness update interrupts our page load, this will never return
@@ -977,78 +995,85 @@ GeckoDriver.prototype.get = function*(cm
  * On Desktop this returns a string representation of the URL of the
  * current top level browsing context.  This is equivalent to
  * document.location.href.
  *
  * When in the context of the chrome, this returns the canonical URL
  * of the current resource.
  */
 GeckoDriver.prototype.getCurrentUrl = function (cmd) {
+  let win = assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
-      return this.getCurrentWindow().location.href;
+      return win.location.href;
 
     case Context.CONTENT:
-      let isB2G = this.appName == "B2G";
-      return this.listener.getCurrentUrl(isB2G);
+      return this.listener.getCurrentUrl();
   }
 };
 
 /** Gets the current title of the window. */
 GeckoDriver.prototype.getTitle = function* (cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       resp.body.value = win.document.documentElement.getAttribute("title");
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getTitle();
       break;
   }
 };
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function (cmd, resp) {
-  let win = this.getCurrentWindow();
+  let win = assert.window(this.getCurrentWindow());
+
   resp.body.value = win.document.documentElement.getAttribute("windowtype");
 };
 
 /** Gets the page source of the content document. */
 GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let s = new win.XMLSerializer();
       resp.body.value = s.serializeToString(win.document);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getPageSource();
       break;
   }
 };
 
 /** Go back in history. */
 GeckoDriver.prototype.goBack = function*(cmd, resp) {
   assert.content(this.context);
+  assert.window(this.getCurrentWindow());
 
   yield this.listener.goBack();
 };
 
 /** Go forward in history. */
 GeckoDriver.prototype.goForward = function*(cmd, resp) {
   assert.content(this.context);
+  assert.window(this.getCurrentWindow());
 
   yield this.listener.goForward();
 };
 
 /** Refresh the page. */
 GeckoDriver.prototype.refresh = function*(cmd, resp) {
   assert.content(this.context);
+  assert.window(this.getCurrentWindow());
 
   yield this.listener.refresh();
 };
 
 /**
  * Forces an update for the given browser's id.
  */
 GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
@@ -1085,16 +1110,18 @@ GeckoDriver.prototype.getIdForBrowser = 
  * Return an opaque server-assigned identifier to this window that
  * uniquely identifies it within this Marionette instance.  This can
  * be used to switch to this window at a later point.
  *
  * @return {string}
  *     Unique window handle.
  */
 GeckoDriver.prototype.getWindowHandle = function (cmd, resp) {
+  assert.window(this.getCurrentWindow(Context.CONTENT));
+
   // curFrameId always holds the current tab.
   if (this.curBrowser.curFrameId) {
     resp.body.value = this.curBrowser.curFrameId;
     return;
   }
 
   for (let i in this.browsers) {
     if (this.curBrowser == this.browsers[i]) {
@@ -1126,16 +1153,18 @@ GeckoDriver.prototype.getWindowHandles =
  * Return an opaque server-assigned identifier to this window that
  * uniquely identifies it within this Marionette instance.  This can
  * be used to switch to this window at a later point.
  *
  * @return {string}
  *     Unique window handle.
  */
 GeckoDriver.prototype.getChromeWindowHandle = function (cmd, resp) {
+  assert.window(this.getCurrentWindow(Context.CHROME));
+
   for (let i in this.browsers) {
     if (this.curBrowser == this.browsers[i]) {
       resp.body.value = i;
       return;
     }
   }
 };
 
@@ -1152,17 +1181,17 @@ GeckoDriver.prototype.getChromeWindowHan
 
 /**
  * Get the current window position.
  *
  * @return {Object.<string, number>}
  *     Object with |x| and |y| coordinates.
  */
 GeckoDriver.prototype.getWindowPosition = function (cmd, resp) {
-  let win = this.getCurrentWindow();
+  let win = assert.window(this.getCurrentWindow());
   return {
     x: win.screenX,
     y: win.screenY,
   };
 };
 
 /**
  * Set the window position of the browser on the OS Window Manager
@@ -1173,23 +1202,23 @@ GeckoDriver.prototype.getWindowPosition 
  * @param {number} y
  *     Y coordinate of the top/left of the window that it will be
  *     moved to.
  *
  * @return {Object.<string, number>}
  *     Object with |x| and |y| coordinates.
  */
 GeckoDriver.prototype.setWindowPosition = function* (cmd, resp) {
-  assert.firefox()
+  assert.firefox();
+  let win = assert.window(this.getCurrentWindow());
 
   let {x, y} = cmd.parameters;
   assert.positiveInteger(x);
   assert.positiveInteger(y);
 
-  let win = this.getCurrentWindow();
   let orig = {screenX: win.screenX, screenY: win.screenY};
 
   win.moveTo(x, y);
   yield wait.until((resolve, reject) => {
     if ((x == win.screenX && y == win.screenY) ||
       (win.screenX != orig.screenX || win.screenY != orig.screenY)) {
       resolve();
     } else {
@@ -1278,16 +1307,18 @@ GeckoDriver.prototype.switchToWindow = f
       }
     }
   } else {
     throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
   }
 };
 
 GeckoDriver.prototype.getActiveFrame = function (cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       // no frame means top-level
       resp.body.value = null;
       if (this.curFrame) {
         let elRef = this.curBrowser.seenEls
             .add(this.curFrame.frameElement);
         let el = element.makeWebElement(elRef);
@@ -1301,29 +1332,33 @@ GeckoDriver.prototype.getActiveFrame = f
         let el = element.makeWebElement(this.currentFrameElement);
         resp.body.value = el;
       }
       break;
   }
 };
 
 GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let res = yield this.listener.switchToParentFrame();
 };
 
 /**
  * Switch to a given frame within the current window.
  *
  * @param {Object} element
  *     A web element reference to the element to switch to.
  * @param {(string|number)} id
  *     If element is not defined, then this holds either the id, name,
  *     or index of the frame to switch to.
  */
 GeckoDriver.prototype.switchToFrame = function* (cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let {id, element, focus} = cmd.parameters;
 
   const otherErrorsExpr = /about:.+(error)|(blocked)\?/;
   const checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
   let curWindow = this.getCurrentWindow();
 
   let checkLoad = function() {
@@ -1505,16 +1540,18 @@ GeckoDriver.prototype.setTimeouts = func
 
   // merge with existing timeouts
   let merged = Object.assign(this.timeouts.toJSON(), json);
   this.timeouts = session.Timeouts.fromJSON(merged);
 };
 
 /** Single tap. */
 GeckoDriver.prototype.singleTap = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let {id, x, y} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'singleTap' is not yet available in chrome context");
 
     case Context.CONTENT:
@@ -1529,30 +1566,34 @@ GeckoDriver.prototype.singleTap = functi
  *
  * @param {Array.<?>} actions
  *     Array of objects that each represent an action sequence.
  *
  * @throws {UnsupportedOperationError}
  *     If the command is made in chrome context.
  */
 GeckoDriver.prototype.performActions = function(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'performActions' is not yet available in chrome context");
 
     case Context.CONTENT:
       return this.listener.performActions({"actions": cmd.parameters.actions});
   }
 };
 
 /**
  * Release all the keys and pointer buttons that are currently depressed.
  */
 GeckoDriver.prototype.releaseActions = function(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'releaseActions' is not yet available in chrome context");
 
     case Context.CONTENT:
         return this.listener.releaseActions();
   }
@@ -1564,25 +1605,26 @@ GeckoDriver.prototype.releaseActions = f
  * @param {Object} value
  *     A nested array where the inner array represents each event,
  *     and the outer array represents a collection of events.
  *
  * @return {number}
  *     Last touch ID.
  */
 GeckoDriver.prototype.actionChain = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {chain, nextId} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       // be conservative until this has a use case and is established
       // to work as expected in Fennec
-      assert.firefox()
-
-      let win = this.getCurrentWindow();
+      assert.firefox();
+
       resp.body.value = yield this.legacyactions.dispatchActions(
           chain, nextId, {frame: win}, this.curBrowser.seenEls);
       break;
 
     case Context.CONTENT:
       this.addFrameCloseListener("action chain");
       resp.body.value = yield this.listener.actionChain(chain, nextId);
       break;
@@ -1593,16 +1635,18 @@ GeckoDriver.prototype.actionChain = func
  * A multi-action chain.
  *
  * @param {Object} value
  *     A nested array where the inner array represents eache vent,
  *     the middle array represents a collection of events for each
  *     finger, and the outer array represents all fingers.
  */
 GeckoDriver.prototype.multiAction = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'multiAction' is not yet available in chrome context");
 
     case Context.CONTENT:
       this.addFrameCloseListener("multi action chain");
       yield this.listener.multiAction(cmd.parameters.value, cmd.parameters.max_length);
@@ -1614,31 +1658,33 @@ GeckoDriver.prototype.multiAction = func
  * Find an element using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  */
 GeckoDriver.prototype.findElement = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
     all: false,
   };
 
   switch (this.context) {
     case Context.CHROME:
       if (!SUPPORTED_STRATEGIES.has(strategy)) {
         throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
       }
 
-      let container = {frame: this.getCurrentWindow()};
+      let container = {frame: win};
       if (opts.startNode) {
         opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
       }
       let el = yield element.find(container, strategy, expr, opts);
       let elRef = this.curBrowser.seenEls.add(el);
       let webEl = element.makeWebElement(elRef);
 
       resp.body.value = webEl;
@@ -1657,31 +1703,33 @@ GeckoDriver.prototype.findElement = func
  * Find elements using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  */
 GeckoDriver.prototype.findElements = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
     all: true,
   };
 
   switch (this.context) {
     case Context.CHROME:
       if (!SUPPORTED_STRATEGIES.has(strategy)) {
         throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
       }
 
-      let container = {frame: this.getCurrentWindow()};
+      let container = {frame: win};
       if (opts.startNode) {
         opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
       }
       let els = yield element.find(container, strategy, expr, opts);
 
       let elRefs = this.curBrowser.seenEls.addAll(els);
       let webEls = elRefs.map(element.makeWebElement);
       resp.body = webEls;
@@ -1693,16 +1741,18 @@ GeckoDriver.prototype.findElements = fun
           cmd.parameters.value,
           opts);
       break;
   }
 };
 
 /** Return the active element on the page. */
 GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'getActiveElement' is not yet available in chrome context");
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getActiveElement();
       break;
@@ -1711,21 +1761,22 @@ GeckoDriver.prototype.getActiveElement =
 
 /**
  * Send click event to element.
  *
  * @param {string} id
  *     Reference ID to the element that will be clicked.
  */
 GeckoDriver.prototype.clickElement = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       yield interaction.clickElement(el, this.a11yChecks);
       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
@@ -1743,21 +1794,22 @@ GeckoDriver.prototype.clickElement = fun
  *     Web element reference ID to the element that will be inspected.
  * @param {string} name
  *     Name of the attribute which value to retrieve.
  *
  * @return {string}
  *     Value of the attribute.
  */
 GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
 
       resp.body.value = el.getAttribute(name);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getElementAttribute(id, name);
       break;
@@ -1771,21 +1823,22 @@ GeckoDriver.prototype.getElementAttribut
  *     Web element reference ID to the element that will be inspected.
  * @param {string} name
  *     Name of the property which value to retrieve.
  *
  * @return {string}
  *     Value of the property.
  */
 GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el[name];
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getElementProperty(id, name);
       break;
   }
@@ -1794,22 +1847,23 @@ GeckoDriver.prototype.getElementProperty
 /**
  * Get the text of an element, if any.  Includes the text of all child
  * elements.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
 GeckoDriver.prototype.getElementText = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // for chrome, we look at text nodes, and any node with a "label" field
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let lines = [];
       this.getVisibleText(el, lines);
       resp.body.value = lines.join("\n");
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getElementText(id);
@@ -1819,21 +1873,22 @@ GeckoDriver.prototype.getElementText = f
 
 /**
  * Get the tag name of the element.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
 GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el.tagName.toLowerCase();
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getElementTagName(id);
       break;
   }
@@ -1841,21 +1896,22 @@ GeckoDriver.prototype.getElementTagName 
 
 /**
  * Check if element is displayed.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
 GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = yield interaction.isElementDisplayed(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.isElementDisplayed(id);
       break;
@@ -1866,21 +1922,22 @@ GeckoDriver.prototype.isElementDisplayed
  * Return the property of the computed style of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  * @param {string} propertyName
  *     CSS rule that is being requested.
  */
 GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {id, propertyName: prop} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let sty = win.document.defaultView.getComputedStyle(el);
       resp.body.value = sty.getPropertyValue(prop);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getElementValueOfCssProperty(id, prop);
       break;
@@ -1889,22 +1946,23 @@ GeckoDriver.prototype.getElementValueOfC
 
 /**
  * Check if element is enabled.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  */
 GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = yield interaction.isElementEnabled(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.isElementEnabled(id);
       break;
@@ -1913,39 +1971,41 @@ GeckoDriver.prototype.isElementEnabled =
 
 /**
  * Check if element is selected.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  */
 GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = yield interaction.isElementSelected(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.isElementSelected(id);
       break;
   }
 };
 
 GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let rect = el.getBoundingClientRect();
       resp.body = {
         x: rect.x + win.pageXOffset,
         y: rect.y + win.pageYOffset,
         width: rect.width,
         height: rect.height
       };
@@ -1961,53 +2021,57 @@ GeckoDriver.prototype.getElementRect = f
  * Send key presses to element after focusing on it.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  * @param {string} value
  *     Value to send to the element.
  */
 GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {id, value} = cmd.parameters;
   assert.defined(value, `Expected character sequence: ${value}`);
 
   switch (this.context) {
     case Context.CHROME:
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       yield interaction.sendKeysToElement(
           el, value, true, this.a11yChecks);
       break;
 
     case Context.CONTENT:
       yield this.listener.sendKeysToElement(id, value);
       break;
   }
 };
 
 /** Sets the test name.  The test name is used for logging purposes. */
 GeckoDriver.prototype.setTestName = function*(cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let val = cmd.parameters.value;
   this.testName = val;
   yield this.listener.setTestName({value: val});
 };
 
 /**
  * Clear the text of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be cleared.
  */
 GeckoDriver.prototype.clearElement = function*(cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // the selenium atom doesn't work here
-      let win = this.getCurrentWindow();
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       if (el.nodeName == "textbox") {
         el.value = "";
       } else if (el.nodeName == "checkbox") {
         el.checked = false;
       }
       break;
 
@@ -2019,25 +2083,27 @@ GeckoDriver.prototype.clearElement = fun
 
 /**
  * Switch to shadow root of the given host element.
  *
  * @param {string} id element id.
  */
 GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
   assert.content(this.context)
+  assert.window(this.getCurrentWindow());
 
   let id;
   if (cmd.parameters) { id = cmd.parameters.id; }
   yield this.listener.switchToShadowRoot(id);
 };
 
 /** Add a cookie to the document. */
 GeckoDriver.prototype.addCookie = function*(cmd, resp) {
   assert.content(this.context)
+  assert.window(this.getCurrentWindow());
 
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:addCookie", cb);
     let cookie = msg.json;
     Services.cookies.add(
         cookie.domain,
         cookie.path,
         cookie.name,
@@ -2057,23 +2123,25 @@ GeckoDriver.prototype.addCookie = functi
 /**
  * Get all the cookies for the current domain.
  *
  * This is the equivalent of calling {@code document.cookie} and parsing
  * the result.
  */
 GeckoDriver.prototype.getCookies = function*(cmd, resp) {
   assert.content(this.context)
+  assert.window(this.getCurrentWindow());
 
   resp.body = yield this.listener.getCookies();
 };
 
 /** Delete all cookies that are visible to a document. */
 GeckoDriver.prototype.deleteAllCookies = function*(cmd, resp) {
   assert.content(this.context)
+  assert.window(this.getCurrentWindow());
 
   let cb = msg => {
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
         false,
@@ -2084,16 +2152,17 @@ GeckoDriver.prototype.deleteAllCookies =
   this.mm.addMessageListener("Marionette:deleteCookie", cb);
   yield this.listener.deleteAllCookies();
   this.mm.removeMessageListener("Marionette:deleteCookie", cb);
 };
 
 /** Delete a cookie by name. */
 GeckoDriver.prototype.deleteCookie = function*(cmd, resp) {
   assert.content(this.context)
+  assert.window(this.getCurrentWindow());
 
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:deleteCookie", cb);
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
@@ -2113,19 +2182,21 @@ GeckoDriver.prototype.deleteCookie = fun
  * Otherwise the window itself will be closed. If it is the last window
  * currently open, the window will not be closed to prevent a shutdown of the
  * application. Instead the returned list of window handles is empty.
  *
  * @return {Array.<string>}
  *     Unique window handles of remaining windows.
  */
 GeckoDriver.prototype.close = function (cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   let nwins = 0;
+
   let winEn = Services.wm.getEnumerator(null);
-
   while (winEn.hasMoreElements()) {
     let win = winEn.getNext();
 
     // For browser windows count the tabs. Otherwise take the window itself.
     let tabbrowser = browser.getTabBrowser(win);
     if (tabbrowser) {
       nwins += tabbrowser.tabs.length;
     } else {
@@ -2154,21 +2225,21 @@ GeckoDriver.prototype.close = function (
  * closed to prevent a shutdown of the application. Instead the returned
  * list of chrome window handles is empty.
  *
  * @return {Array.<string>}
  *     Unique chrome window handles of remaining chrome windows.
  */
 GeckoDriver.prototype.closeChromeWindow = function (cmd, resp) {
   assert.firefox();
-
-  // Get the total number of windows
+  assert.window(this.getCurrentWindow(Context.CHROME));
+
   let nwins = 0;
+
   let winEn = Services.wm.getEnumerator(null);
-
   while (winEn.hasMoreElements()) {
     nwins++;
     winEn.getNext();
   }
 
   // If there is only 1 window left, do not close it. Instead return a faked
   // empty array of window handles. This will instruct geckodriver to terminate
   // the application.
@@ -2239,16 +2310,18 @@ GeckoDriver.prototype.deleteSession = fu
   cert.uninstallOverride();
 
   this.sessionId = null;
   this.capabilities = new session.Capabilities();
 };
 
 /** Returns the current status of the Application Cache. */
 GeckoDriver.prototype.getAppCacheStatus = function* (cmd, resp) {
+  assert.window(this.getCurrentWindow());
+
   switch (this.context) {
     case Context.CHROME:
       throw new UnsupportedOperationError(
           "Command 'getAppCacheStatus' is not yet available in chrome context");
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getAppCacheStatus();
       break;
@@ -2311,26 +2384,25 @@ GeckoDriver.prototype.clearImportedScrip
  *     scroll to the element.
  *
  * @return {string}
  *     If {@code hash} is false, PNG image encoded as base64 encoded string. If
  *     'hash' is True, hex digest of the SHA-256 hash of the base64 encoded
  *     string.
  */
 GeckoDriver.prototype.takeScreenshot = function (cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
+
   let {id, highlights, full, hash, scroll} = cmd.parameters;
   highlights = highlights || [];
   let format = hash ? capture.Format.Hash : capture.Format.Base64;
 
   switch (this.context) {
     case Context.CHROME:
-      let container = {frame: this.getCurrentWindow().document.defaultView};
-      if (!container.frame) {
-        throw new NoSuchWindowError("Unable to locate window");
-      }
+      let container = {frame: win.document.defaultView};
 
       let highlightEls = highlights.map(
           ref => this.curBrowser.seenEls.get(ref, container));
 
       // viewport
       let canvas;
       if (!id && !full) {
         canvas = capture.viewport(container.frame, highlightEls);
@@ -2365,62 +2437,63 @@ GeckoDriver.prototype.takeScreenshot = f
  * Get the current browser orientation.
  *
  * Will return one of the valid primary orientation values
  * portrait-primary, landscape-primary, portrait-secondary, or
  * landscape-secondary.
  */
 GeckoDriver.prototype.getScreenOrientation = function (cmd, resp) {
   assert.fennec();
-
-  resp.body.value = this.getCurrentWindow().screen.mozOrientation;
+  let win = assert.window(this.getCurrentWindow());
+
+  resp.body.value = win.screen.mozOrientation;
 };
 
 /**
  * Set the current browser orientation.
  *
  * The supplied orientation should be given as one of the valid
  * orientation values.  If the orientation is unknown, an error will
  * be raised.
  *
  * Valid orientations are "portrait" and "landscape", which fall
  * back to "portrait-primary" and "landscape-primary" respectively,
  * and "portrait-secondary" as well as "landscape-secondary".
  */
 GeckoDriver.prototype.setScreenOrientation = function (cmd, resp) {
   assert.fennec();
+  let win = assert.window(this.getCurrentWindow());
 
   const ors = [
     "portrait", "landscape",
     "portrait-primary", "landscape-primary",
     "portrait-secondary", "landscape-secondary",
   ];
 
   let or = String(cmd.parameters.orientation);
   assert.string(or);
   let mozOr = or.toLowerCase();
   if (!ors.includes(mozOr)) {
     throw new InvalidArgumentError(`Unknown screen orientation: ${or}`);
   }
 
-  let win = this.getCurrentWindow();
   if (!win.screen.mozLockOrientation(mozOr)) {
     throw new WebDriverError(`Unable to set screen orientation: ${or}`);
   }
 };
 
 /**
  * Get the size of the browser window currently in focus.
  *
  * Will return the current browser window size in pixels. Refers to
  * window outerWidth and outerHeight values, which include scroll bars,
  * title bars, etc.
  */
 GeckoDriver.prototype.getWindowSize = function (cmd, resp) {
-  let win = this.getCurrentWindow();
+  let win = assert.window(this.getCurrentWindow());
   return {
     width: win.outerWidth,
     height: win.outerHeight,
   };
 };
 
 /**
  * Set the size of the browser window currently in focus.
@@ -2434,19 +2507,19 @@ GeckoDriver.prototype.getWindowSize = fu
  * @param {number} height
  *     Requested window outer height.
  *
  * @return {Map.<string, number>}
  *     New outerWidth/outerHeight dimensions.
  */
 GeckoDriver.prototype.setWindowSize = function* (cmd, resp) {
   assert.firefox()
+  let win = assert.window(this.getCurrentWindow());
 
   const {width, height} = cmd.parameters;
-  const win = this.getCurrentWindow();
 
   yield new Promise(resolve => {
     // When the DOM resize event claims that it fires _after_ the document
     // view has been resized, it is lying.
     //
     // Because resize events fire at a high rate, DOM modifications
     // such as updates to outerWidth/outerHeight are not guaranteed to
     // have processed.  To overcome this... abomination... of the web
@@ -2468,77 +2541,80 @@ GeckoDriver.prototype.setWindowSize = fu
 /**
  * Maximizes the user agent window as if the user pressed the maximise
  * button.
  *
  * Not Supported on B2G or Fennec.
  */
 GeckoDriver.prototype.maximizeWindow = function (cmd, resp) {
   assert.firefox()
-
-  let win = this.getCurrentWindow();
+  let win = assert.window(this.getCurrentWindow());
+
   win.maximize()
 };
 
 /**
  * Dismisses a currently displayed tab modal, or returns no such alert if
  * no modal is displayed.
  */
 GeckoDriver.prototype.dismissDialog = function (cmd, resp) {
+  assert.window(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   let {button0, button1} = this.dialog.ui;
   (button1 ? button1 : button0).click();
   this.dialog = null;
 };
 
 /**
  * Accepts a currently displayed tab modal, or returns no such alert if
  * no modal is displayed.
  */
 GeckoDriver.prototype.acceptDialog = function (cmd, resp) {
+  assert.window(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   let {button0} = this.dialog.ui;
   button0.click();
   this.dialog = null;
 };
 
 /**
  * Returns the message shown in a currently displayed modal, or returns a no such
  * alert error if no modal is currently displayed.
  */
 GeckoDriver.prototype.getTextFromDialog = function (cmd, resp) {
+  assert.window(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   let {infoBody} = this.dialog.ui;
   resp.body.value = infoBody.textContent;
 };
 
 /**
  * Sends keys to the input field of a currently displayed modal, or
  * returns a no such alert error if no modal is currently displayed. If
  * a tab modal is currently displayed but has no means for text input,
  * an element not visible error is returned.
  */
 GeckoDriver.prototype.sendKeysToDialog = function (cmd, resp) {
+  let win = assert.window(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   // see toolkit/components/prompts/content/commonDialog.js
   let {loginContainer, loginTextbox} = this.dialog.ui;
   if (loginContainer.hidden) {
     throw new ElementNotVisibleError("This prompt does not accept text input");
   }
 
-  let win = this.dialog.window ? this.dialog.window : this.getCurrentWindow();
   event.sendKeysToElement(
       cmd.parameters.value,
       loginTextbox,
       {ignoreVisibility: true},
-      win);
+      this.dialog.window ? this.dialog.window : win);
 };
 
 GeckoDriver.prototype._checkIfAlertIsPresent = function() {
   if (!this.dialog || !this.dialog.ui) {
     throw new NoAlertOpenError(
         "No tab modal was open when attempting to get the dialog text");
   }
 };
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py
@@ -1,34 +1,39 @@
 # 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/.
 
 from marionette_driver.by import By
 
-from marionette_harness import MarionetteTestCase
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
-class TestClickChrome(MarionetteTestCase):
+class TestClickChrome(WindowManagerMixin, MarionetteTestCase):
+
     def setUp(self):
-        MarionetteTestCase.setUp(self)
-        self.root_window = self.marionette.current_window_handle
+        super(TestClickChrome, self).setUp()
+
         self.marionette.set_context("chrome")
-        self.marionette.execute_script(
-            "window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen')")
-        self.marionette.switch_to_window("foo")
-        self.assertNotEqual(self.root_window, self.marionette.current_window_handle)
 
     def tearDown(self):
-        self.assertNotEqual(self.root_window, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close()")
-        self.marionette.switch_to_window(self.root_window)
-        MarionetteTestCase.tearDown(self)
+        self.close_all_windows()
+
+        super(TestClickChrome, self).tearDown()
 
     def test_click(self):
+
+        def open_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen'); """)
+
+        win = self.open_window(open_with_js)
+        self.marionette.switch_to_window(win)
+
         def checked():
             return self.marionette.execute_script(
                 "return arguments[0].checked",
                 script_args=[box])
 
         box = self.marionette.find_element(By.ID, "testBox")
         self.assertFalse(checked())
         box.click()
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py
@@ -1,85 +1,58 @@
 # 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/.
 
 from marionette_driver.by import By
 
-from marionette_harness import MarionetteTestCase, skip
+from marionette_harness import MarionetteTestCase, skip, WindowManagerMixin
 
 
-class TestIsElementEnabledChrome(MarionetteTestCase):
+class TestElementState(WindowManagerMixin, MarionetteTestCase):
+
     def setUp(self):
-        MarionetteTestCase.setUp(self)
+        super(TestElementState, self).setUp()
+
         self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
+
+        def open_window_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen');
+            """)
+
+        self.win = self.open_window(open_window_with_js)
+        self.marionette.switch_to_window(self.win)
 
     def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
+        self.close_all_windows()
+
+        super(TestElementState, self).tearDown()
+
+    @skip("Switched off in bug 896043, and to be turned on in bug 896046")
+    def test_is_displayed(self):
+        l = self.marionette.find_element(By.ID, "textInput")
+        self.assertTrue(l.is_displayed())
+        self.marionette.execute_script("arguments[0].hidden = true;", [l])
+        self.assertFalse(l.is_displayed())
+        self.marionette.execute_script("arguments[0].hidden = false;", [l])
 
     def test_enabled(self):
         l = self.marionette.find_element(By.ID, "textInput")
         self.assertTrue(l.is_enabled())
         self.marionette.execute_script("arguments[0].disabled = true;", [l])
         self.assertFalse(l.is_enabled())
         self.marionette.execute_script("arguments[0].disabled = false;", [l])
 
     def test_can_get_element_rect(self):
         l = self.marionette.find_element(By.ID, "textInput")
         rect = l.rect
         self.assertTrue(rect['x'] > 0)
         self.assertTrue(rect['y'] > 0)
 
-
-@skip("Switched off in bug 896043, and to be turned on in bug 896046")
-class TestIsElementDisplayed(MarionetteTestCase):
-    def test_isDisplayed(self):
-        l = self.marionette.find_element(By.ID, "textInput")
-        self.assertTrue(l.is_displayed())
-        self.marionette.execute_script("arguments[0].hidden = true;", [l])
-        self.assertFalse(l.is_displayed())
-        self.marionette.execute_script("arguments[0].hidden = false;", [l])
-
-
-class TestGetElementAttributeChrome(MarionetteTestCase):
-    def setUp(self):
-        MarionetteTestCase.setUp(self)
-        self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
-    def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
-
-    def test_get(self):
+    def test_get_attribute(self):
         el = self.marionette.execute_script("return window.document.getElementById('textInput');")
         self.assertEqual(el.get_attribute("id"), "textInput")
 
-class TestGetElementProperty(MarionetteTestCase):
-    def setUp(self):
-        MarionetteTestCase.setUp(self)
-        self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
-    def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
-
-    def test_get(self):
+    def test_get_property(self):
         el = self.marionette.execute_script("return window.document.getElementById('textInput');")
         self.assertEqual(el.get_property("id"), "textInput")
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
@@ -309,35 +309,16 @@ class TestExecuteChrome(WindowManagerMix
 
     def test_async_script_timeout(self):
         with self.assertRaises(errors.ScriptTimeoutException):
             self.marionette.execute_async_script("""
                 var cb = arguments[arguments.length - 1];
                 setTimeout(function() { cb() }, 250);
                 """, script_timeout=100)
 
-    @skip_if_mobile("New windows not supported in Fennec")
-    def test_invalid_chrome_handle(self):
-        try:
-            win = self.open_window()
-            self.marionette.switch_to_window(win)
-
-            # Close new window and don't switch back to the original one
-            self.marionette.close_chrome_window()
-            self.assertNotEqual(self.start_window, win)
-
-            # Call execute_script on an invalid chrome handle
-            with self.marionette.using_context('chrome'):
-                self.marionette.execute_script("""
-                    return true;
-                """)
-
-        finally:
-            self.close_all_windows()
-
     def test_lasting_side_effects(self):
         pass
 
     def test_return_web_element(self):
         pass
 
     def test_return_web_element_array(self):
         pass
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py
@@ -1,33 +1,39 @@
 # 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/.
 
 from marionette_driver.by import By
 from marionette_driver.errors import NoSuchElementException
 from marionette_driver.marionette import HTMLElement
 
-from marionette_harness import MarionetteTestCase
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
-class TestElementsChrome(MarionetteTestCase):
+class TestElementsChrome(WindowManagerMixin, MarionetteTestCase):
+
     def setUp(self):
-        MarionetteTestCase.setUp(self)
+        super(TestElementsChrome, self).setUp()
+
         self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
+
+        def open_window_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen');
+            """)
+
+        win = self.open_window(open_window_with_js)
+        self.marionette.switch_to_window(win)
 
     def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
+        self.close_all_windows()
+
+        super(TestElementsChrome, self).tearDown()
 
     def test_id(self):
         el = self.marionette.execute_script("return window.document.getElementById('textInput');")
         found_el = self.marionette.find_element(By.ID, "textInput")
         self.assertEqual(HTMLElement, type(found_el))
         self.assertEqual(el, found_el)
 
     def test_that_we_can_find_elements_from_css_selectors(self):
@@ -45,38 +51,49 @@ class TestElementsChrome(MarionetteTestC
 
     def test_child_elements(self):
         el = self.marionette.find_element(By.ID, "textInput3")
         parent = self.marionette.find_element(By.ID, "things")
         found_els = parent.find_elements(By.TAG_NAME, "textbox")
         self.assertTrue(el.id in [found_el.id for found_el in found_els])
 
     def test_tag_name(self):
-        el = self.marionette.execute_script("return window.document.getElementsByTagName('vbox')[0];")
+        el = self.marionette.execute_script(
+            "return window.document.getElementsByTagName('vbox')[0];")
         found_el = self.marionette.find_element(By.TAG_NAME, "vbox")
         self.assertEquals('vbox', found_el.tag_name)
         self.assertEqual(HTMLElement, type(found_el))
         self.assertEqual(el, found_el)
 
     def test_class_name(self):
-        el = self.marionette.execute_script("return window.document.getElementsByClassName('asdf')[0];")
+        el = self.marionette.execute_script(
+            "return window.document.getElementsByClassName('asdf')[0];")
         found_el = self.marionette.find_element(By.CLASS_NAME, "asdf")
         self.assertEqual(HTMLElement, type(found_el))
         self.assertEqual(el, found_el)
 
     def test_xpath(self):
         el = self.marionette.execute_script("return window.document.getElementById('testBox');")
         found_el = self.marionette.find_element(By.XPATH, "id('testBox')")
         self.assertEqual(HTMLElement, type(found_el))
         self.assertEqual(el, found_el)
 
     def test_not_found(self):
         self.marionette.timeout.implicit = 1
-        self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
+        self.assertRaises(NoSuchElementException,
+                          self.marionette.find_element, By.ID, "I'm not on the page")
         self.marionette.timeout.implicit = 0
-        self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
+        self.assertRaises(NoSuchElementException,
+                          self.marionette.find_element, By.ID, "I'm not on the page")
 
     def test_timeout(self):
         self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "myid")
         self.marionette.timeout.implicit = 4
-        self.marionette.execute_script("window.setTimeout(function() {var b = window.document.createElement('button'); b.id = 'myid'; document.getElementById('things').appendChild(b);}, 1000)")
+        self.marionette.execute_script("""
+            window.setTimeout(function () {
+              var b = window.document.createElement('button');
+              b.id = 'myid';
+              document.getElementById('things').appendChild(b);
+            }, 1000); """)
         self.assertEqual(HTMLElement, type(self.marionette.find_element(By.ID, "myid")))
-        self.marionette.execute_script("window.document.getElementById('things').removeChild(window.document.getElementById('myid'));")
+        self.marionette.execute_script("""
+            var elem = window.document.getElementById('things');
+            elem.removeChild(window.document.getElementById('myid')); """)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_management.py
@@ -0,0 +1,168 @@
+# 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/.
+
+from marionette_driver import By
+from marionette_driver.errors import NoSuchWindowException
+
+from marionette_harness import MarionetteTestCase, WindowManagerMixin, skip_if_mobile
+
+
+class TestNoSuchWindowContent(WindowManagerMixin, MarionetteTestCase):
+
+    def setUp(self):
+        super(TestNoSuchWindowContent, self).setUp()
+
+    def tearDown(self):
+        self.close_all_windows()
+        super(TestNoSuchWindowContent, self).tearDown()
+
+    @skip_if_mobile("Fennec doesn't support other chrome windows")
+    def test_closed_chrome_window(self):
+
+        def open_with_link():
+            with self.marionette.using_context("content"):
+                test_page = self.marionette.absolute_url("windowHandles.html")
+                self.marionette.navigate(test_page)
+                self.marionette.find_element(By.ID, "new-window").click()
+
+        win = self.open_window(open_with_link)
+        self.marionette.switch_to_window(win)
+        self.marionette.close_chrome_window()
+
+        # When closing a browser window both handles are not available
+        for context in ("chrome", "content"):
+            with self.marionette.using_context(context):
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_chrome_window_handle
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_window_handle
+
+        self.marionette.switch_to_window(self.start_window)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(win)
+
+    @skip_if_mobile("Fennec doesn't support other chrome windows")
+    def test_closed_chrome_window_while_in_frame(self):
+
+        def open_window_with_js():
+            with self.marionette.using_context("chrome"):
+                self.marionette.execute_script("""
+                  window.open('chrome://marionette/content/test.xul',
+                              'foo', 'chrome,centerscreen');
+                """)
+
+        win = self.open_window(trigger=open_window_with_js)
+        self.marionette.switch_to_window(win)
+        with self.marionette.using_context("chrome"):
+            self.marionette.switch_to_frame("iframe")
+        self.marionette.close_chrome_window()
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.current_window_handle
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_window)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(win)
+
+    def test_closed_tab(self):
+        with self.marionette.using_context("content"):
+            tab = self.open_tab()
+            self.marionette.switch_to_window(tab)
+            self.marionette.close()
+
+        # Check that only the content window is not available in both contexts
+        for context in ("chrome", "content"):
+            with self.marionette.using_context(context):
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_window_handle
+                self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_tab)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(tab)
+
+    def test_closed_tab_while_in_frame(self):
+        with self.marionette.using_context("content"):
+            tab = self.open_tab()
+            self.marionette.switch_to_window(tab)
+            self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
+            frame = self.marionette.find_element(By.ID, "test_iframe")
+            self.marionette.switch_to_frame(frame)
+            self.marionette.close()
+
+            with self.assertRaises(NoSuchWindowException):
+                self.marionette.current_window_handle
+            self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_tab)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(tab)
+
+
+class TestNoSuchWindowChrome(TestNoSuchWindowContent):
+
+    def setUp(self):
+        super(TestNoSuchWindowChrome, self).setUp()
+        self.marionette.set_context("chrome")
+
+    def tearDown(self):
+        self.close_all_windows()
+        super(TestNoSuchWindowChrome, self).tearDown()
+
+
+class TestSwitchWindow(WindowManagerMixin, MarionetteTestCase):
+
+    def setUp(self):
+        super(TestSwitchWindow, self).setUp()
+        self.marionette.set_context("chrome")
+
+    def tearDown(self):
+        self.close_all_windows()
+        super(TestSwitchWindow, self).tearDown()
+
+    def test_windows(self):
+        def open_browser_with_js():
+            self.marionette.execute_script(" window.open(); ")
+
+        new_window = self.open_window(trigger=open_browser_with_js)
+        self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
+
+        # switch to the other window
+        self.marionette.switch_to_window(new_window)
+        self.assertEqual(self.marionette.current_chrome_window_handle, new_window)
+        self.assertNotEqual(self.marionette.current_chrome_window_handle, self.start_window)
+
+        # switch back and close original window
+        self.marionette.switch_to_window(self.start_window)
+        self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
+        self.marionette.close_chrome_window()
+
+        self.assertNotIn(self.start_window, self.marionette.chrome_window_handles)
+        self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows))
+
+    def test_should_load_and_close_a_window(self):
+        def open_window_with_link():
+            test_html = self.marionette.absolute_url("test_windows.html")
+            with self.marionette.using_context("content"):
+                self.marionette.navigate(test_html)
+                self.marionette.find_element(By.LINK_TEXT, "Open new window").click()
+
+        new_window = self.open_window(trigger=open_window_with_link)
+        self.marionette.switch_to_window(new_window)
+        self.assertEqual(self.marionette.current_chrome_window_handle, new_window)
+        self.assertEqual(len(self.marionette.chrome_window_handles), 2)
+
+        with self.marionette.using_context('content'):
+            self.assertEqual(self.marionette.title, "We Arrive Here")
+
+        # Let's close and check
+        self.marionette.close_chrome_window()
+        self.marionette.switch_to_window(self.start_window)
+        self.assertEqual(len(self.marionette.chrome_window_handles), 1)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_status_chrome.py
@@ -0,0 +1,24 @@
+# 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/.
+
+import os
+import sys
+
+# add this directory to the path
+sys.path.append(os.path.dirname(__file__))
+
+from test_window_status_content import TestNoSuchWindowContent
+
+
+class TestNoSuchWindowChrome(TestNoSuchWindowContent):
+
+    def setUp(self):
+        super(TestNoSuchWindowChrome, self).setUp()
+
+        self.marionette.set_context("chrome")
+
+    def tearDown(self):
+        self.close_all_windows()
+
+        super(TestNoSuchWindowChrome, self).tearDown()
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_status_content.py
@@ -0,0 +1,115 @@
+# 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/.
+
+from marionette_driver import By
+from marionette_driver.errors import NoSuchWindowException
+
+from marionette_harness import MarionetteTestCase, WindowManagerMixin, skip_if_mobile
+
+
+class TestNoSuchWindowContent(WindowManagerMixin, MarionetteTestCase):
+
+    def setUp(self):
+        super(TestNoSuchWindowContent, self).setUp()
+
+        self.test_page = self.marionette.absolute_url("windowHandles.html")
+        with self.marionette.using_context("content"):
+            self.marionette.navigate(self.test_page)
+
+    def tearDown(self):
+        self.close_all_windows()
+        super(TestNoSuchWindowContent, self).tearDown()
+
+    def open_tab_in_foreground(self):
+        with self.marionette.using_context("content"):
+            link = self.marionette.find_element(By.ID, "new-tab")
+            link.click()
+
+    @skip_if_mobile("Fennec doesn't support other chrome windows")
+    def test_closed_chrome_window(self):
+
+        def open_with_link():
+            with self.marionette.using_context("content"):
+                test_page = self.marionette.absolute_url("windowHandles.html")
+                self.marionette.navigate(test_page)
+                self.marionette.find_element(By.ID, "new-window").click()
+
+        win = self.open_window(open_with_link)
+        self.marionette.switch_to_window(win)
+        self.marionette.close_chrome_window()
+
+        # When closing a browser window both handles are not available
+        for context in ("chrome", "content"):
+            with self.marionette.using_context(context):
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_chrome_window_handle
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_window_handle
+
+        self.marionette.switch_to_window(self.start_window)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(win)
+
+    @skip_if_mobile("Fennec doesn't support other chrome windows")
+    def test_closed_chrome_window_while_in_frame(self):
+
+        def open_window_with_js():
+            with self.marionette.using_context("chrome"):
+                self.marionette.execute_script("""
+                  window.open('chrome://marionette/content/test.xul',
+                              'foo', 'chrome,centerscreen');
+                """)
+
+        win = self.open_window(trigger=open_window_with_js)
+        self.marionette.switch_to_window(win)
+        with self.marionette.using_context("chrome"):
+            self.marionette.switch_to_frame("iframe")
+        self.marionette.close_chrome_window()
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.current_window_handle
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_window)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(win)
+
+    def test_closed_tab(self):
+        with self.marionette.using_context("content"):
+            tab = self.open_tab(self.open_tab_in_foreground)
+            self.marionette.switch_to_window(tab)
+            self.marionette.close()
+
+        # Check that only the content window is not available in both contexts
+        for context in ("chrome", "content"):
+            with self.marionette.using_context(context):
+                with self.assertRaises(NoSuchWindowException):
+                    self.marionette.current_window_handle
+                self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_tab)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(tab)
+
+    def test_closed_tab_while_in_frame(self):
+        with self.marionette.using_context("content"):
+            tab = self.open_tab(self.open_tab_in_foreground)
+            self.marionette.switch_to_window(tab)
+            self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
+            frame = self.marionette.find_element(By.ID, "test_iframe")
+            self.marionette.switch_to_frame(frame)
+            self.marionette.close()
+
+            with self.assertRaises(NoSuchWindowException):
+                self.marionette.current_window_handle
+            self.marionette.current_chrome_window_handle
+
+        self.marionette.switch_to_window(self.start_tab)
+
+        with self.assertRaises(NoSuchWindowException):
+            self.marionette.switch_to_window(tab)
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py
@@ -1,26 +1,33 @@
 # 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/.
 
-from marionette_harness import MarionetteTestCase
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
-class TestTitleChrome(MarionetteTestCase):
+class TestTitleChrome(WindowManagerMixin, MarionetteTestCase):
+
     def setUp(self):
-        MarionetteTestCase.setUp(self)
+        super(TestTitleChrome, self).setUp()
+
         self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
 
     def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
+        self.close_all_windows()
+
+        super(TestTitleChrome, self).tearDown()
 
     def test_get_chrome_title(self):
-        title = self.marionette.execute_script("return window.document.documentElement.getAttribute('title');")
+
+        def open_window_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen');
+            """)
+
+        win = self.open_window(open_window_with_js)
+        self.marionette.switch_to_window(win)
+
+        title = self.marionette.execute_script(
+            "return window.document.documentElement.getAttribute('title');")
         self.assertEqual(title, self.marionette.title)
-        self.assertEqual('Title Test', self.marionette.title)
rename from testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py
rename to testing/marionette/harness/marionette_harness/tests/unit/test_window_type_chrome.py
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_type_chrome.py
@@ -1,27 +1,33 @@
 # 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/.
 
-from marionette_harness import MarionetteTestCase
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
-class TestWindowTypeChrome(MarionetteTestCase):
+class TestWindowTypeChrome(WindowManagerMixin, MarionetteTestCase):
+
     def setUp(self):
-        MarionetteTestCase.setUp(self)
+        super(TestWindowTypeChrome, self).setUp()
+
         self.marionette.set_context("chrome")
-        self.win = self.marionette.current_window_handle
-        self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
-        self.marionette.switch_to_window('foo')
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
 
     def tearDown(self):
-        self.assertNotEqual(self.win, self.marionette.current_window_handle)
-        self.marionette.execute_script("window.close();")
-        self.marionette.switch_to_window(self.win)
-        MarionetteTestCase.tearDown(self)
+        self.close_all_windows()
+
+        super(TestWindowTypeChrome, self).tearDown()
 
     def test_get_window_type(self):
-        window_type = self.marionette.execute_script("return window.document.documentElement.getAttribute('windowtype');")
+
+        def open_window_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen');
+            """)
+
+        win = self.open_window(open_window_with_js)
+        self.marionette.switch_to_window(win)
+
+        window_type = self.marionette.execute_script(
+            "return window.document.documentElement.getAttribute('windowtype');")
         self.assertEqual(window_type, self.marionette.get_window_type())
-        self.assertEqual('Test Type', self.marionette.get_window_type())
-
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -71,23 +71,25 @@ skip-if = appname == 'fennec'
 [test_window_handles_chrome.py]
 skip-if = appname == 'fennec'
 [test_window_handles_content.py]
 [test_window_close_chrome.py]
 skip-if = appname == 'fennec'
 [test_window_close_content.py]
 [test_window_position.py]
 skip-if = appname == 'fennec'
+[test_window_status_content.py]
+[test_window_status_chrome.py]
 
 [test_screenshot.py]
 [test_cookies.py]
 [test_window_title.py]
 [test_window_title_chrome.py]
 skip-if = appname == 'fennec'
-[test_window_type.py]
+[test_window_type_chrome.py]
 skip-if = appname == 'fennec'
 [test_implicit_waits.py]
 [test_wait.py]
 [test_expected.py]
 [test_date_time_value.py]
 [test_getactiveframe_oop.py]
 skip-if = true # Bug 925688
 [test_chrome_async_finish.js]
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -1093,22 +1093,18 @@ function cancelRequest() {
   if (onDOMContentLoaded) {
     removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
   }
 }
 
 /**
  * Get URL of the top-level browsing context.
  */
-function getCurrentUrl(isB2G) {
-  if (isB2G) {
-    return curContainer.frame.location.href;
-  } else {
-    return content.location.href;
-  }
+function getCurrentUrl() {
+  return content.location.href;
 }
 
 /**
  * Get the title of the current browsing context.
  */
 function getTitle() {
   return curContainer.frame.top.document.title;
 }