Bug 1430109 - Combine assert.window and assert.contentBrowser. r?maja_zf draft
authorAndreas Tolfsen <ato@sny.no>
Fri, 12 Jan 2018 14:25:30 +0000
changeset 720165 908a554bd59a08c914a20d0b15d1e017fff8f6ce
parent 720151 f40f5ac940c145d2e484c4f94032b3006e5a7a4f
child 745988 f0b9ec2770bb4eaee100af481f7c5b2d6ce5932f
push id95460
push userbmo:ato@sny.no
push dateSun, 14 Jan 2018 15:14:24 +0000
reviewersmaja_zf
bugs1430109
milestone59.0a1
Bug 1430109 - Combine assert.window and assert.contentBrowser. r?maja_zf The forthcoming window tracking refactoring introduces the new abstractions ContentContext and ChromeContext that to a large extent share the same interface. They make it possible to interact with both types of browsing context in a uniform manner. Marionette currently has a lot of convoluted if-conditions to paper over the differences between ChromeWindow, <xul:browser>, and browser.Context. Examples of this includes the assert.window and assert.contentBrowser assertions: they essentially perform the same job, but does not share the same API because the underlying APIs they call are different. In an effort to prepare Marionette for the window tracking refactoring, this patch adds a bit of glue to combine them both into one assertion called assert.open. This checks that the browsing context has not been discarded. MozReview-Commit-ID: K5e7Sr1mq0
testing/marionette/assert.js
testing/marionette/browser.js
testing/marionette/driver.js
testing/marionette/test_assert.js
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -4,27 +4,33 @@
 
 "use strict";
 
 const {utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const {
   InvalidArgumentError,
   InvalidSessionIDError,
   JavaScriptError,
   NoSuchWindowError,
   UnexpectedAlertOpenError,
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 
+XPCOMUtils.defineLazyGetter(this, "browser", () => {
+  const {browser} = Cu.import("chrome://marionette/content/browser.js", {});
+  return browser;
+});
+
 this.EXPORTED_SYMBOLS = ["assert"];
 
 const isFennec = () => AppConstants.platform == "android";
 const isFirefox = () =>
     Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
 
 /**
  * Shorthands for common assertions made in Marionette.
@@ -120,55 +126,46 @@ assert.fennec = function(msg = "") {
  *     If <var>context</var> is not content.
  */
 assert.content = function(context, msg = "") {
   msg = msg || "Only supported in content context";
   assert.that(c => c.toString() == "content", msg, UnsupportedOperationError)(context);
 };
 
 /**
- * Asserts that |win| is open.
- *
- * @param {ChromeWindow} win
- *     Chrome window to test.
- * @param {string=} msg
- *     Custom error message.
- *
- * @return {ChromeWindow}
- *     <var>win</var> is returned unaltered.
+ * Asserts that the {@link ChromeWindow} is open or that the {@link
+ * browser.Context} has a content browser attached.
  *
- * @throws {NoSuchWindowError}
- *     If <var>win</var> has been closed.
- */
-assert.window = function(win, msg = "") {
-  msg = msg || "Unable to locate window";
-  return assert.that(w => w && !w.closed,
-      msg,
-      NoSuchWindowError)(win);
-};
-
-/**
- * Asserts that |context| is a valid browsing context.
+ * When passed in a {@link ChromeContext} this is equivalent to
+ * testing that the associated <code>window</code> global is open,
+ * and when given {@link browser.Context} it will test that the content
+ * frame, represented by <code>&lt;xul:browser&gt;</code>, is
+ * connected.
  *
- * @param {browser.Context} context
+ * @param {(ChromeWindow|browser.Context)} context
  *     Browsing context to test.
  * @param {string=} msg
  *     Custom error message.
  *
+ * @return {(ChromeWindow|browser.Context)}
+ *     <var>context</var> is returned unaltered.
+ *
  * @throws {NoSuchWindowError}
- *     If |context| is invalid.
+ *     If <var>context</var>'s <code>window</code> has been closed.
  */
-assert.contentBrowser = function(context, msg = "") {
+assert.open = function(context, msg = "") {
   // TODO: The contentBrowser uses a cached tab, which is only updated when
   // switchToTab is called. Because of that an additional check is needed to
   // make sure that the chrome window has not already been closed.
-  assert.window(context && context.window);
+  if (context instanceof browser.Context) {
+    assert.open(context.window);
+  }
 
-  msg = msg || "Current window does not have a content browser";
-  assert.that(c => c.contentBrowser,
+  msg = msg || "Browsing context has been discarded";
+  return assert.that(ctx => ctx && !ctx.closed,
       msg,
       NoSuchWindowError)(context);
 };
 
 /**
  * Asserts that there is no current user prompt.
  *
  * @param {modal.Dialog} dialog
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -170,16 +170,30 @@ browser.Context = class {
     return null;
   }
 
   get messageManager() {
     return this.contentBrowser.messageManager;
   }
 
   /**
+   * Checks if the browsing context has been discarded.
+   *
+   * The browsing context will have been discarded if the content
+   * browser, represented by the <code>&lt;xul:browser&gt;</code>,
+   * has been detached.
+   *
+   * @return {boolean}
+   *     True if browsing context has been discarded, false otherwise.
+   */
+  get closed() {
+    return this.contentBrowser === null;
+  }
+
+  /**
    * The current frame ID is managed per browser element on desktop in
    * case the ID needs to be refreshed. The currently selected window is
    * identified by a tab.
    */
   get curFrameId() {
     let rv = null;
     if (this.tab || this.driver.isReftestBrowser(this.contentBrowser)) {
       rv = this.getIdForBrowser(this.contentBrowser);
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -867,17 +867,17 @@ GeckoDriver.prototype.getContext = funct
  *
  * @throws {ScriptTimeoutError}
  *     If the script was interrupted due to reaching the
  *     <var>scriptTimeout</var> or default timeout.
  * @throws {JavaScriptError}
  *     If an {@link Error} was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeScript = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(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,
@@ -944,17 +944,17 @@ GeckoDriver.prototype.executeScript = as
  *
  * @throws {ScriptTimeoutError}
  *     If the script was interrupted due to reaching the
  *     <var>scriptTimeout</var> or default timeout.
  * @throws {JavaScriptError}
  *     If an Error was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeAsyncScript = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(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,
@@ -1027,17 +1027,17 @@ GeckoDriver.prototype.execute_ = async f
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.get = async function(cmd) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let url = cmd.parameters.url;
 
   let get = this.listener.get({url, pageTimeout: this.timeouts.pageLoad});
 
   // If a reload of the frame script interrupts our page load, this will
   // never return. We need to re-issue this request to correctly poll for
@@ -1069,17 +1069,17 @@ GeckoDriver.prototype.get = async functi
  * of the current resource.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getCurrentUrl = function() {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   return this.currentURL.toString();
 };
 
 /**
  * Gets the current title of the window.
  *
@@ -1087,25 +1087,25 @@ GeckoDriver.prototype.getCurrentUrl = fu
  *     Document title of the top-level browsing context.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getTitle = function() {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   return this.title;
 };
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
 
   resp.body.value = this.windowType;
 };
 
 /**
  * Gets the page source of the content document.
  *
  * @return {string}
@@ -1113,17 +1113,17 @@ GeckoDriver.prototype.getWindowType = fu
  *     active document.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getPageSource = async function(cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   switch (this.context) {
     case Context.Chrome:
       let s = new win.XMLSerializer();
       resp.body.value = s.serializeToString(win.document);
       break;
 
@@ -1141,17 +1141,17 @@ GeckoDriver.prototype.getPageSource = as
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.goBack = async function() {
   assert.content(this.context);
-  assert.contentBrowser(this.curBrowser);
+  assert.open(this.curBrowser);
   this._assertAndDismissModal();
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
     return;
   }
 
   let lastURL = this.currentURL;
@@ -1183,17 +1183,17 @@ GeckoDriver.prototype.goBack = async fun
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.goForward = async function() {
   assert.content(this.context);
-  assert.contentBrowser(this.curBrowser);
+  assert.open(this.curBrowser);
   this._assertAndDismissModal();
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
     return;
   }
 
   let lastURL = this.currentURL;
@@ -1226,17 +1226,17 @@ GeckoDriver.prototype.goForward = async 
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.refresh = async function() {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let refresh = this.listener.refresh(
       {pageTimeout: this.timeouts.pageLoad});
 
   // If a reload of the frame script interrupts our page load, this will
   // never return. We need to re-issue this request to correctly poll for
   // readyState and send errors.
@@ -1293,17 +1293,17 @@ GeckoDriver.prototype.getIdForBrowser = 
  *
  * @return {string}
  *     Unique window handle.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  */
 GeckoDriver.prototype.getWindowHandle = function() {
-  assert.contentBrowser(this.curBrowser);
+  assert.open(this.curBrowser);
 
   return this.curBrowser.curFrameId.toString();
 };
 
 /**
  * Get a list of top-level browsing contexts. On desktop this typically
  * corresponds to the set of open tabs for browser windows, or the window
  * itself for non-browser chrome windows.
@@ -1328,17 +1328,17 @@ GeckoDriver.prototype.getWindowHandles =
  *
  * @return {string}
  *     Unique window handle.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  */
 GeckoDriver.prototype.getChromeWindowHandle = function(cmd, resp) {
-  assert.window(this.getCurrentWindow(Context.Chrome));
+  assert.open(this.getCurrentWindow(Context.Chrome));
 
   for (let i in this.browsers) {
     if (this.curBrowser == this.browsers[i]) {
       resp.body.value = i;
       return;
     }
   }
 };
@@ -1366,17 +1366,17 @@ GeckoDriver.prototype.getChromeWindowHan
  *     of browser window.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getWindowRect = function() {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
   return this.curBrowser.rect;
 };
 
 /**
  * Set the window position and size of the browser on the operating
  * system window manager.
  *
@@ -1403,17 +1403,17 @@ GeckoDriver.prototype.getWindowRect = fu
  *     Not applicable to application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.setWindowRect = async function(cmd) {
   assert.firefox();
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {x, y, width, height} = cmd.parameters;
   let origRect = this.curBrowser.rect;
 
   // Synchronous resize to |width| and |height| dimensions.
   async function resizeWindow(width, height) {
     return new Promise(resolve => {
@@ -1602,17 +1602,17 @@ GeckoDriver.prototype.setWindowHandle = 
     if ("tabIndex" in winProperties) {
       this.curBrowser.switchToTab(
           winProperties.tabIndex, winProperties.win, focus);
     }
   }
 };
 
 GeckoDriver.prototype.getActiveFrame = function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
 
   switch (this.context) {
     case Context.Chrome:
       // no frame means top-level
       resp.body.value = null;
       if (this.curFrame) {
         resp.body.value = this.curBrowser.seenEls.add(
             this.curFrame.frameElement);
@@ -1633,17 +1633,17 @@ GeckoDriver.prototype.getActiveFrame = f
  * of the current browsing context.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.switchToParentFrame = async function() {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   await this.listener.switchToParentFrame();
 };
 
 /**
  * Switch to a given frame within the current window.
  *
@@ -1654,17 +1654,17 @@ GeckoDriver.prototype.switchToParentFram
  *     or index of the frame to switch to.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.switchToFrame = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {id, focus} = cmd.parameters;
 
   // TODO(ato): element can be either string (deprecated) or a web
   // element JSON Object.  Can be removed with Firefox 60.
   let byFrame;
   if (typeof cmd.parameters.element == "string") {
@@ -1837,17 +1837,17 @@ GeckoDriver.prototype.getTimeouts = func
 GeckoDriver.prototype.setTimeouts = function(cmd) {
   // merge with existing timeouts
   let merged = Object.assign(this.timeouts.toJSON(), cmd.parameters);
   this.timeouts = session.Timeouts.fromJSON(merged);
 };
 
 /** Single tap. */
 GeckoDriver.prototype.singleTap = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
 
   let {id, x, y} = cmd.parameters;
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       throw new UnsupportedOperationError(
           "Command 'singleTap' is not yet available in chrome context");
@@ -1869,17 +1869,17 @@ GeckoDriver.prototype.singleTap = async 
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.performActions = async function(cmd) {
   assert.content(this.context,
       "Command 'performActions' is not yet available in chrome context");
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let actions = cmd.parameters.actions;
   await this.listener.performActions({"actions": actions});
 };
 
 /**
  * Release all the keys and pointer buttons that are currently depressed.
@@ -1888,17 +1888,17 @@ GeckoDriver.prototype.performActions = a
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.releaseActions = async function() {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   await this.listener.releaseActions();
 };
 
 /**
  * An action chain.
  *
@@ -1912,17 +1912,17 @@ GeckoDriver.prototype.releaseActions = a
  * @throws {UnsupportedOperationError}
  *     Not applicable to application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.actionChain = async function(cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   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
@@ -1950,17 +1950,17 @@ GeckoDriver.prototype.actionChain = asyn
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.multiAction = async function(cmd) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {value, max_length} = cmd.parameters; // eslint-disable-line camelcase
   await this.listener.multiAction(value, max_length);
 };
 
 /**
  * Find an element using the indicated search strategy.
@@ -1971,17 +1971,17 @@ GeckoDriver.prototype.multiAction = asyn
  *     Value the client is looking for.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.findElement = async function(cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {using, value} = cmd.parameters;
   let startNode;
   if (typeof cmd.parameters.element != "undefined") {
     startNode = WebElement.fromUUID(cmd.parameters.element, this.context);
   }
 
@@ -2017,17 +2017,17 @@ GeckoDriver.prototype.findElement = asyn
  * 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 = async function(cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
 
   let {using, value} = cmd.parameters;
   let startNode;
   if (typeof cmd.parameters.element != "undefined") {
     startNode = WebElement.fromUUID(cmd.parameters.element, this.context);
   }
 
   let opts = {
@@ -2071,17 +2071,17 @@ GeckoDriver.prototype.findElements = asy
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  * @throws {NoSuchElementError}
  *     If the document does not have an active element, i.e. if
  *     its document element has been deleted.
  */
 GeckoDriver.prototype.getActiveElement = async function() {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   return this.listener.getActiveElement();
 };
 
 /**
  * Send click event to element.
  *
@@ -2093,17 +2093,17 @@ GeckoDriver.prototype.getActiveElement =
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.clickElement = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2149,17 +2149,17 @@ GeckoDriver.prototype.clickElement = asy
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementAttribute = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let name = assert.string(cmd.parameters.name);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
@@ -2189,17 +2189,17 @@ GeckoDriver.prototype.getElementAttribut
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementProperty = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let name = assert.string(cmd.parameters.name);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
@@ -2228,17 +2228,17 @@ GeckoDriver.prototype.getElementProperty
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementText = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       // for chrome, we look at text nodes, and any node with a "label" field
@@ -2268,17 +2268,17 @@ GeckoDriver.prototype.getElementText = a
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementTagName = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2305,17 +2305,17 @@ GeckoDriver.prototype.getElementTagName 
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.isElementDisplayed = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2346,17 +2346,17 @@ GeckoDriver.prototype.isElementDisplayed
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementValueOfCssProperty = async function(
     cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let prop = assert.string(cmd.parameters.propertyName);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
@@ -2386,17 +2386,17 @@ GeckoDriver.prototype.getElementValueOfC
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.isElementEnabled = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       // Selenium atom doesn't quite work here
@@ -2425,17 +2425,17 @@ GeckoDriver.prototype.isElementEnabled =
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.isElementSelected = async function(cmd, resp) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       // Selenium atom doesn't quite work here
@@ -2456,17 +2456,17 @@ GeckoDriver.prototype.isElementSelected 
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getElementRect = async function(cmd, resp) {
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2498,17 +2498,17 @@ GeckoDriver.prototype.getElementRect = a
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.sendKeysToElement = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let text = assert.string(cmd.parameters.text);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
@@ -2533,17 +2533,17 @@ GeckoDriver.prototype.sendKeysToElement 
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.clearElement = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
 
   switch (this.context) {
     case Context.Chrome:
       // the selenium atom doesn't work here
@@ -2569,17 +2569,17 @@ GeckoDriver.prototype.clearElement = asy
  *
  * @throws {InvalidArgumentError}
  *     If <var>id</var> is not a string.
  * @throws {NoSuchElementError}
  *     If element represented by reference <var>id</var> is unknown.
  */
 GeckoDriver.prototype.switchToShadowRoot = async function(cmd) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
 
   let id = assert.string(cmd.parameters.id);
   let webEl = WebElement.fromUUID(id, this.context);
   await this.listener.switchToShadowRoot(webEl);
 };
 
 /**
  * Add a single cookie to the cookie store associated with the active
@@ -2595,17 +2595,17 @@ GeckoDriver.prototype.switchToShadowRoot
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  * @throws {InvalidCookieDomainError}
  *     If <var>cookie</var> is for a different domain than the active
  *     document's host.
  */
 GeckoDriver.prototype.addCookie = function(cmd) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {protocol, hostname} = this.currentURL;
 
   const networkSchemes = ["ftp:", "http:", "https:"];
   if (!networkSchemes.includes(protocol)) {
     throw new InvalidCookieDomainError("Document is cookie-averse");
   }
@@ -2625,17 +2625,17 @@ GeckoDriver.prototype.addCookie = functi
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getCookies = function(cmd, resp) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {hostname, pathname} = this.currentURL;
   resp.body = [...cookie.iter(hostname, pathname)];
 };
 
 /**
  * Delete all cookies that are visible to a document.
@@ -2644,17 +2644,17 @@ GeckoDriver.prototype.getCookies = funct
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.deleteAllCookies = function() {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {hostname, pathname} = this.currentURL;
   for (let toDelete of cookie.iter(hostname, pathname)) {
     cookie.remove(toDelete);
   }
 };
 
@@ -2665,17 +2665,17 @@ GeckoDriver.prototype.deleteAllCookies =
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.deleteCookie = function(cmd) {
   assert.content(this.context);
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   let {hostname, pathname} = this.currentURL;
   let name = assert.string(cmd.parameters.name);
   for (let c of cookie.iter(hostname, pathname)) {
     if (c.name === name) {
       cookie.remove(c);
     }
@@ -2695,17 +2695,17 @@ GeckoDriver.prototype.deleteCookie = fun
  *     Unique window handles of remaining windows.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.close = async function() {
-  assert.window(this.getCurrentWindow(Context.Content));
+  assert.open(this.getCurrentWindow(Context.Content));
   this._assertAndDismissModal();
 
   let nwins = 0;
 
   for (let win of this.windows) {
     // For browser windows count the tabs. Otherwise take the window itself.
     let tabbrowser = browser.getTabBrowser(win);
     if (tabbrowser && tabbrowser.tabs) {
@@ -2733,17 +2733,17 @@ GeckoDriver.prototype.close = async func
  * 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 = async function() {
   assert.firefox();
-  assert.window(this.getCurrentWindow(Context.Chrome));
+  assert.open(this.getCurrentWindow(Context.Chrome));
 
   let nwins = 0;
 
   // eslint-disable-next-line
   for (let _ of this.windows) {
     nwins++;
   }
 
@@ -2840,17 +2840,17 @@ GeckoDriver.prototype.deleteSession = fu
  *     scroll to the element.
  *
  * @return {string}
  *     If <var>hash</var> is false, PNG image encoded as Base64 encoded
  *     string.  If <var>hash</var> is true, hex digest of the SHA-256
  *     hash of the Base64 encoded string.
  */
 GeckoDriver.prototype.takeScreenshot = function(cmd) {
-  let win = assert.window(this.getCurrentWindow());
+  let win = assert.open(this.getCurrentWindow());
 
   let {id, highlights, full, hash} = cmd.parameters;
   highlights = highlights || [];
   let format = hash ? capture.Format.Hash : capture.Format.Base64;
 
   switch (this.context) {
     case Context.Chrome:
       let highlightEls = highlights
@@ -2895,17 +2895,17 @@ 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();
-  let win = assert.window(this.getCurrentWindow());
+  let win = assert.open(this.getCurrentWindow());
 
   resp.body.value = win.screen.mozOrientation;
 };
 
 /**
  * Set the current browser orientation.
  *
  * The supplied orientation should be given as one of the valid
@@ -2913,17 +2913,17 @@ GeckoDriver.prototype.getScreenOrientati
  * 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) {
   assert.fennec();
-  let win = assert.window(this.getCurrentWindow());
+  let win = assert.open(this.getCurrentWindow());
 
   const ors = [
     "portrait", "landscape",
     "portrait-primary", "landscape-primary",
     "portrait-secondary", "landscape-secondary",
   ];
 
   let or = String(cmd.parameters.orientation);
@@ -2953,17 +2953,17 @@ GeckoDriver.prototype.setScreenOrientati
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.minimizeWindow = async function() {
   assert.firefox();
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   if (WindowState.from(win.windowState) == WindowState.Fullscreen) {
     await exitFullscreen(win);
   }
 
   if (WindowState.from(win.windowState) != WindowState.Minimized) {
     await new Promise(resolve => {
@@ -2990,17 +2990,17 @@ GeckoDriver.prototype.minimizeWindow = a
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.maximizeWindow = async function() {
   assert.firefox();
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   switch (WindowState.from(win.windowState)) {
     case WindowState.Fullscreen:
       await exitFullscreen(win);
       break;
 
     case WindowState.Minimized:
@@ -3076,17 +3076,17 @@ GeckoDriver.prototype.maximizeWindow = a
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.fullscreenWindow = async function() {
   assert.firefox();
-  const win = assert.window(this.getCurrentWindow());
+  const win = assert.open(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   if (WindowState.from(win.windowState) == WindowState.Minimized) {
     await restoreWindow(win, this.curBrowser.eventObserver);
   }
 
   if (WindowState.from(win.windowState) != WindowState.Fullscreen) {
     await new Promise(resolve => {
@@ -3098,43 +3098,43 @@ GeckoDriver.prototype.fullscreenWindow =
   return this.curBrowser.rect;
 };
 
 /**
  * Dismisses a currently displayed tab modal, or returns no such alert if
  * no modal is displayed.
  */
 GeckoDriver.prototype.dismissDialog = function() {
-  assert.window(this.getCurrentWindow());
+  assert.open(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() {
-  assert.window(this.getCurrentWindow());
+  assert.open(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());
+  assert.open(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   let {infoBody} = this.dialog.ui;
   resp.body.value = infoBody.textContent;
 };
 
 /**
  * Set the user prompt's value field.
@@ -3151,17 +3151,17 @@ GeckoDriver.prototype.getTextFromDialog 
  *     If the current user prompt is an alert or confirm.
  * @throws {NoSuchAlertError}
  *     If there is no current user prompt.
  * @throws {UnsupportedOperationError}
  *     If the current user prompt is something other than an alert,
  *     confirm, or a prompt.
  */
 GeckoDriver.prototype.sendKeysToDialog = async function(cmd) {
-  assert.window(this.getCurrentWindow());
+  assert.open(this.getCurrentWindow());
   this._checkIfAlertIsPresent();
 
   // see toolkit/components/prompts/content/commonDialog.js
   let {loginTextbox} = this.dialog.ui;
   await interaction.sendKeysToElement(
       loginTextbox, cmd.parameters.text, this.a11yChecks);
 };
 
--- a/testing/marionette/test_assert.js
+++ b/testing/marionette/test_assert.js
@@ -164,37 +164,24 @@ add_test(function test_string() {
   assert.string(`bar`);
   Assert.throws(() => assert.string(42), InvalidArgumentError);
 
   Assert.throws(() => assert.string(42, "custom"), /custom/);
 
   run_next_test();
 });
 
-add_test(function test_window() {
-  assert.window({closed: false});
+add_test(function test_open() {
+  assert.open({closed: false});
 
   for (let typ of [null, undefined, {closed: true}]) {
-    Assert.throws(() => assert.window(typ), NoSuchWindowError);
+    Assert.throws(() => assert.open(typ), NoSuchWindowError);
   }
 
-  Assert.throws(() => assert.window(null, "custom"), /custom/);
-
-  run_next_test();
-});
-
-add_test(function test_contentBrowser() {
-  assert.contentBrowser({contentBrowser: 42, window: {closed: false}});
-
-  let closedWindow = {contentBrowser: 42, window: {closed: true}};
-  let noContentBrowser = {contentBrowser: null, window: {closed: false}};
-
-  for (let typ of [null, undefined, closedWindow, noContentBrowser]) {
-    Assert.throws(() => assert.contentBrowser(typ), NoSuchWindowError);
-  }
+  Assert.throws(() => assert.open(null, "custom"), /custom/);
 
   run_next_test();
 });
 
 add_test(function test_object() {
   assert.object({});
   assert.object(new Object());
   for (let typ of [42, "foo", true, null, undefined]) {