Bug 1359004 - Add preliminary support for unexpected alerts draft
authorAndreas Tolfsen <ato@mozilla.com>
Thu, 20 Apr 2017 18:00:46 +0100
changeset 567890 6a6ac55615760feb0aa6ff70f5a0bc71fd765d3d
parent 567802 f229b7e5d91eb70d23d3e31db7caff9d69a2ef04
child 625791 4c67a0193e4474313edccd6b4fcbdf41c7ac47b6
push id55725
push userbmo:ato@mozilla.com
push dateTue, 25 Apr 2017 16:56:22 +0000
bugs1359004, 1264259
milestone55.0a1
Bug 1359004 - Add preliminary support for unexpected alerts Add preliminary support for returning unexpected alert open errors when calling commands that require it according to the WebDriver standard. Also fixes a faulty test that seems to believe it is fine to click an element whilst an alert is present. Further work needs to be done on user prompts, asserts, and the handler for user prompts in https://bugzilla.mozilla.org/show_bug.cgi?id=1264259. MozReview-Commit-ID: BiWURoQECji
testing/marionette/assert.js
testing/marionette/driver.js
testing/marionette/error.js
testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
testing/marionette/test_assert.js
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -137,17 +137,34 @@ assert.window = function (win, msg = "")
     try {
       return w && w.document.defaultView;
 
     // If the window is no longer available a TypeError is thrown.
     } catch (e if e.name === "TypeError") {
       return null;
     }
   }, msg, NoSuchWindowError)(win);
-}
+};
+
+/**
+ * Asserts that there is no current user prompt.
+ *
+ * @param {modal.Dialog} dialog
+ *     Reference to current dialogue.
+ * @param {string=} msg
+ *     Custom error message.
+ *
+ * @throws {UnexpectedAlertOpenError}
+ *     If there is a user prompt.
+ */
+assert.noUserPrompt = function (dialog, msg = "") {
+  assert.that(d => d === null || typeof d == "undefined",
+      msg,
+      UnexpectedAlertOpenError)(dialog);
+};
 
 /**
  * Asserts that |obj| is defined.
  *
  * @param {?} obj
  *     Value to test.
  * @param {string=} msg
  *     Custom error message.
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -966,20 +966,28 @@ GeckoDriver.prototype.executeJSScript = 
  * current window triggers and document.readyState is "complete".
  *
  * In chrome context it will change the current window's location to
  * the supplied URL and wait until document.readyState equals "complete"
  * or the page timeout duration has elapsed.
  *
  * @param {string} url
  *     URL to navigate to.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function* (cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let url = cmd.parameters.url;
 
   let get = this.listener.get({url: url, pageTimeout: this.timeouts.pageLoad});
 
   // If a remoteness update interrupts our page load, this will never return
   // We need to re-issue this request to correctly poll for readyState and
   // send errors.
@@ -1004,32 +1012,49 @@ GeckoDriver.prototype.get = function* (c
  * Get a string representing the current URL.
  *
  * 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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getCurrentUrl = function (cmd) {
-  let win = assert.window(this.getCurrentWindow());
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   switch (this.context) {
     case Context.CHROME:
       return win.location.href;
 
     case Context.CONTENT:
       return this.listener.getCurrentUrl();
   }
 };
 
-/** Gets the current title of the window. */
+/**
+ * Gets the current title of the window.
+ *
+ * @return {string}
+ *     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* (cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   switch (this.context) {
     case Context.CHROME:
       resp.body.value = win.document.documentElement.getAttribute("title");
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getTitle();
@@ -1039,39 +1064,59 @@ GeckoDriver.prototype.getTitle = functio
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function (cmd, resp) {
   let win = assert.window(this.getCurrentWindow());
 
   resp.body.value = win.document.documentElement.getAttribute("windowtype");
 };
 
-/** Gets the page source of the content document. */
+/**
+ * Gets the page source of the content document.
+ *
+ * @return {string}
+ *     String serialisation of the DOM of the current browsing context's
+ *     active document.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
+ */
 GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   switch (this.context) {
     case Context.CHROME:
       let s = new win.XMLSerializer();
       resp.body.value = s.serializeToString(win.document);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getPageSource();
       break;
   }
 };
 
 /**
  * Cause the browser to traverse one step backward in the joint history
  * of the current browsing context.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function* (cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   if (!this.curBrowser.tab) {
     // Navigation does not work for non-browser windows
     return;
   }
 
   if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
     return;
@@ -1097,20 +1142,28 @@ GeckoDriver.prototype.goBack = function*
   });
 
   yield goBack;
 };
 
 /**
  * Cause the browser to traverse one step forward in the joint history
  * of the current browsing context.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function* (cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   if (!this.curBrowser.tab) {
     // Navigation does not work for non-browser windows
     return;
   }
 
   if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
     return;
@@ -1134,21 +1187,30 @@ GeckoDriver.prototype.goForward = functi
         "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
         parameters);
   });
 
   yield goForward;
 };
 
 /**
- * Causes the browser to reload the page in in current top-level browsing context.
+ * Causes the browser to reload the page in current top-level browsing
+ * context.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function* (cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   yield this.listener.refresh({pageTimeout: this.timeouts.pageLoad});
 };
 
 /**
  * Forces an update for the given browser's id.
  */
 GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
@@ -1259,49 +1321,68 @@ GeckoDriver.prototype.getChromeWindowHan
  *
  * Will return the current browser window size in pixels. Refers to
  * window outerWidth and outerHeight values, which include scroll bars,
  * title bars, etc.
  *
  * @return {Object.<string, number>}
  *     Object with |x| and |y| coordinates, and |width| and |height|
  *     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 (cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
+
   return {
     x: win.screenX,
     y: win.screenY,
     width: win.outerWidth,
     height: win.outerHeight,
   };
 };
 
 /**
- * Set the window position and size of the browser on the OS Window Manager
+ * Set the window position and size of the browser on the operating
+ * system window manager.
  *
- * The supplied width and height values refer to the window outerWidth
+ * The supplied |width| and |height| values refer to the window outerWidth
  * and outerHeight values, which include browser chrome and OS-level
  * window borders.
+ *
  * @param {number} x
  *     X coordinate of the top/left of the window that it will be
  *     moved to.
  * @param {number} y
  *     Y coordinate of the top/left of the window that it will be
  *     moved to.
+ * @param {number} width
+ *     Width to resize the window to.
+ * @param {number} height
+ *     Height to resize the window to.
  *
  * @return {Object.<string, number>}
- *     Object with |x| and |y| coordinates
- *     and |width| and |height| dimensions
+ *     Object with |x| and |y| coordinates and |width| and |height|
+ *     dimensions.
  *
+ * @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.setWindowRect = function* (cmd, resp) {
-  assert.firefox()
-
-  let win = assert.window(this.getCurrentWindow());
+  assert.firefox();
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let {x, y, height, width} = cmd.parameters;
 
   if (height != null && width != null) {
     assert.positiveInteger(height);
     assert.positiveInteger(width);
     yield new Promise(resolve => {
       // When the DOM resize event claims that it fires _after_ the document
@@ -1446,33 +1527,49 @@ GeckoDriver.prototype.getActiveFrame = f
       if (this.currentFrameElement !== null) {
         let el = element.makeWebElement(this.currentFrameElement);
         resp.body.value = el;
       }
       break;
   }
 };
 
-GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
+/**
+ * Set the current browsing context for future commands to the parent
+ * 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 = function* (cmd, resp) {
   assert.window(this.getCurrentWindow());
-
-  let res = yield this.listener.switchToParentFrame();
+  assert.noUserPrompt(this.dialog);
+
+  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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.switchToFrame = function* (cmd, resp) {
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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();
 
@@ -1678,59 +1775,70 @@ GeckoDriver.prototype.singleTap = functi
 
 /**
  * Perform a series of grouped actions at the specified points in time.
  *
  * @param {Array.<?>} actions
  *     Array of objects that each represent an action sequence.
  *
  * @throws {UnsupportedOperationError}
- *     If the command is made in chrome context.
+ *     Not yet 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.performActions = function(cmd, resp) {
+GeckoDriver.prototype.performActions = function (cmd, resp) {
+  assert.content(this.context,
+      "Command 'performActions' is not yet available in chrome context");
   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});
-  }
+  assert.noUserPrompt(this.dialog);
+
+  let actions = cmd.parameters.actions;
+  yield this.listener.performActions({"actions": actions});
 };
 
 /**
  * Release all the keys and pointer buttons that are currently depressed.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function(cmd, resp) {
+  assert.content(this.context);
   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();
-  }
+  assert.noUserPrompt(this.dialog);
+
+  yield this.listener.releaseActions();
 };
 
 /**
  * An action chain.
  *
  * @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.
+ *
+ * @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 = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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();
@@ -1748,42 +1856,51 @@ 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.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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 = function*(cmd, resp) {
+GeckoDriver.prototype.multiAction = function* (cmd, resp) {
+  assert.content(this.context);
   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);
-      break;
-  }
+  assert.noUserPrompt(this.dialog);
+
+  let {value, max_length} = cmd.parameters;
+
+  this.addFrameCloseListener("multi action chain");
+  yield this.listener.multiAction(value, max_length);
 };
 
 /**
  * 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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.findElement = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.findElement = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
     all: false,
   };
@@ -1854,39 +1971,51 @@ GeckoDriver.prototype.findElements = fun
       resp.body = yield this.listener.findElementsContent(
           cmd.parameters.using,
           cmd.parameters.value,
           opts);
       break;
   }
 };
 
-/** Return the active element on the page. */
-GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
+/**
+ * Return the active element on the page.
+ *
+ * @return {WebElement}
+ *     Active element of the current browsing context's document element.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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.getActiveElement = function* (cmd, resp) {
+  assert.content(this.context);
   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;
-  }
+  assert.noUserPrompt(this.dialog);
+
+  resp.body.value = yield this.listener.getActiveElement();
 };
 
 /**
  * Send click event to element.
  *
  * @param {string} id
  *     Reference ID to the element that will be clicked.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.clickElement = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.clickElement = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       yield interaction.clickElement(el, this.a11yChecks);
       break;
@@ -1907,26 +2036,31 @@ GeckoDriver.prototype.clickElement = fun
  *
  * @param {string} id
  *     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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementAttribute = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       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;
   }
 };
@@ -1936,19 +2070,25 @@ GeckoDriver.prototype.getElementAttribut
  *
  * @param {string} id
  *     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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementProperty = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el[name];
       break;
@@ -1960,19 +2100,28 @@ 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.
+ *
+ * @return {string}
+ *     Element's text "as rendered".
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementText = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementText = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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 el = this.curBrowser.seenEls.get(id, {frame: win});
       let lines = [];
@@ -1986,19 +2135,28 @@ GeckoDriver.prototype.getElementText = f
   }
 };
 
 /**
  * Get the tag name of the element.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
+ *
+ * @return {string}
+ *     Local tag name of element.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementTagName = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = el.tagName.toLowerCase();
       break;
@@ -2009,19 +2167,28 @@ GeckoDriver.prototype.getElementTagName 
   }
 };
 
 /**
  * Check if element is displayed.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
+ *
+ * @return {boolean}
+ *     True if displayed, false otherwise.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementDisplayed = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = yield interaction.isElementDisplayed(
           el, this.a11yChecks);
@@ -2035,19 +2202,28 @@ 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.
+ *
+ * @return {string}
+ *     Value of |propertyName|.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.getElementValueOfCssProperty = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let {id, propertyName: prop} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let sty = win.document.defaultView.getComputedStyle(el);
       resp.body.value = sty.getPropertyValue(prop);
@@ -2059,44 +2235,62 @@ GeckoDriver.prototype.getElementValueOfC
   }
 };
 
 /**
  * Check if element is enabled.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
+ *
+ * @return {boolean}
+ *     True if enabled, false if disabled.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementEnabled = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       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;
   }
-},
+};
 
 /**
  * Check if element is selected.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
+ *
+ * @return {boolean}
+ *     True if selected, false if unselected.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.isElementSelected = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       resp.body.value = yield interaction.isElementSelected(
@@ -2104,18 +2298,25 @@ GeckoDriver.prototype.isElementSelected 
       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());
+/**
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
+ */
+GeckoDriver.prototype.getElementRect = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       let rect = el.getBoundingClientRect();
       resp.body = {
@@ -2134,19 +2335,26 @@ 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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.sendKeysToElement = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
+
   let {id, text} = cmd.parameters;
   assert.string(text);
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       yield interaction.sendKeysToElement(
           el, text, true, this.a11yChecks);
@@ -2167,19 +2375,25 @@ GeckoDriver.prototype.setTestName = func
   yield this.listener.setTestName({value: val});
 };
 
 /**
  * Clear the text of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be cleared.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.clearElement = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+GeckoDriver.prototype.clearElement = function* (cmd, resp) {
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // the selenium atom doesn't work here
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       if (el.nodeName == "textbox") {
@@ -2195,29 +2409,38 @@ 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)
+GeckoDriver.prototype.switchToShadowRoot = function* (cmd, resp) {
+  assert.content(this.context);
   assert.window(this.getCurrentWindow());
 
-  let id;
-  if (cmd.parameters) { id = cmd.parameters.id; }
+  let 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)
+/**
+ * Add a cookie to the document.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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.addCookie = function* (cmd, resp) {
+  assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:addCookie", cb);
     let cookie = msg.json;
     Services.cookies.add(
         cookie.domain,
         cookie.path,
         cookie.name,
@@ -2234,28 +2457,46 @@ GeckoDriver.prototype.addCookie = functi
   yield this.listener.addCookie(cmd.parameters.cookie);
 };
 
 /**
  * Get all the cookies for the current domain.
  *
  * This is the equivalent of calling {@code document.cookie} and parsing
  * the result.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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)
+GeckoDriver.prototype.getCookies = function* (cmd, resp) {
+  assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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)
+/**
+ * Delete all cookies that are visible to a document.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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* (cmd, resp) {
+  assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let cb = msg => {
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
         false,
@@ -2263,20 +2504,30 @@ GeckoDriver.prototype.deleteAllCookies =
     return true;
   };
 
   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)
+/**
+ * Delete a cookie by name.
+ *
+ * @throws {UnsupportedOperationError}
+ *     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, resp) {
+  assert.content(this.context);
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:deleteCookie", cb);
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
@@ -2287,26 +2538,33 @@ GeckoDriver.prototype.deleteCookie = fun
 
   this.mm.addMessageListener("Marionette:deleteCookie", cb);
   yield this.listener.deleteCookie(cmd.parameters.name);
 };
 
 /**
  * Close the currently selected tab/window.
  *
- * With multiple open tabs present the currently selected tab will be closed.
- * 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.
+ * With multiple open tabs present the currently selected tab will
+ * be closed.  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.
+ *
+ * @throws {NoSuchWindowError}
+ *     Top-level browsing context has been discarded.
+ * @throws {UnexpectedAlertOpenError}
+ *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.close = function (cmd, resp) {
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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.
@@ -2595,21 +2853,27 @@ GeckoDriver.prototype.setScreenOrientati
     throw new WebDriverError(`Unable to set screen orientation: ${or}`);
   }
 };
 
 /**
  * Maximizes the user agent window as if the user pressed the maximise
  * button.
  *
- * Not Supported on B2G or Fennec.
+ * @throws {UnsupportedOperationError}
+ *     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 = function (cmd, resp) {
-  assert.firefox()
-  let win = assert.window(this.getCurrentWindow());
+  assert.firefox();
+  const win = assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   win.maximize()
 };
 
 /**
  * Dismisses a currently displayed tab modal, or returns no such alert if
  * no modal is displayed.
  */
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -21,16 +21,17 @@ const ERRORS = new Set([
   "NoSuchElementError",
   "NoSuchFrameError",
   "NoSuchWindowError",
   "ScriptTimeoutError",
   "SessionNotCreatedError",
   "StaleElementReferenceError",
   "TimeoutError",
   "UnableToSetCookieError",
+  "UnexpectedAlertOpenError",
   "UnknownCommandError",
   "UnknownError",
   "UnsupportedOperationError",
   "WebDriverError",
 ]);
 
 const BUILTIN_ERRORS = new Set([
   "Error",
@@ -445,16 +446,23 @@ class TimeoutError extends WebDriverErro
 
 class UnableToSetCookieError extends WebDriverError {
   constructor (message) {
     super(message);
     this.status = "unable to set cookie";
   }
 }
 
+class UnexpectedAlertOpenError extends WebDriverError {
+  constructor (message) {
+    super(message);
+    this.status = "unexpected alert open";
+  }
+}
+
 class UnknownCommandError extends WebDriverError {
   constructor (message) {
     super(message);
     this.status = "unknown command";
   }
 }
 
 class UnknownError extends WebDriverError {
@@ -467,32 +475,33 @@ class UnknownError extends WebDriverErro
 class UnsupportedOperationError extends WebDriverError {
   constructor (message) {
     super(message);
     this.status = "unsupported operation";
   }
 }
 
 const STATUSES = new Map([
+  ["element click intercepted", ElementClickInterceptedError],
   ["element not accessible", ElementNotAccessibleError],
   ["element not interactable", ElementNotInteractableError],
-  ["element click intercepted", ElementClickInterceptedError],
   ["insecure certificate", InsecureCertificateError],
   ["invalid argument", InvalidArgumentError],
   ["invalid element state", InvalidElementStateError],
   ["invalid selector", InvalidSelectorError],
   ["invalid session id", InvalidSessionIDError],
   ["javascript error", JavaScriptError],
   ["move target out of bounds", MoveTargetOutOfBoundsError],
   ["no alert open", NoAlertOpenError],
   ["no such element", NoSuchElementError],
   ["no such frame", NoSuchFrameError],
   ["no such window", NoSuchWindowError],
   ["script timeout", ScriptTimeoutError],
   ["session not created", SessionNotCreatedError],
   ["stale element reference", StaleElementReferenceError],
   ["timeout", TimeoutError],
   ["unable to set cookie", UnableToSetCookieError],
+  ["unexpected alert open", UnexpectedAlertOpenError],
   ["unknown command", UnknownCommandError],
   ["unknown error", UnknownError],
   ["unsupported operation", UnsupportedOperationError],
   ["webdriver error", WebDriverError],
 ]);
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
@@ -1,28 +1,28 @@
 # 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 NoAlertPresentException, ElementNotInteractableException
 from marionette_driver.expected import element_present
+from marionette_driver import errors
 from marionette_driver.marionette import Alert
 from marionette_driver.wait import Wait
 
 from marionette_harness import MarionetteTestCase, skip_if_e10s, WindowManagerMixin
 
 
 class BaseAlertTestCase(WindowManagerMixin, MarionetteTestCase):
 
     def alert_present(self):
         try:
             Alert(self.marionette).text
             return True
-        except NoAlertPresentException:
+        except errors.NoAlertPresentException:
             return False
 
     def wait_for_alert(self, timeout=None):
         Wait(self.marionette, timeout=timeout).until(
             lambda _: self.alert_present())
 
     def wait_for_alert_closed(self, timeout=None):
         Wait(self.marionette, timeout=timeout).until(
@@ -48,18 +48,20 @@ class TestTabModalAlerts(BaseAlertTestCa
 
             self.wait_for_alert_closed()
         except:
             pass
 
         super(TestTabModalAlerts, self).tearDown()
 
     def test_no_alert_raises(self):
-        self.assertRaises(NoAlertPresentException, Alert(self.marionette).accept)
-        self.assertRaises(NoAlertPresentException, Alert(self.marionette).dismiss)
+        with self.assertRaises(errors.NoAlertPresentException):
+            Alert(self.marionette).accept()
+        with self.assertRaises(errors.NoAlertPresentException):
+            Alert(self.marionette).dismiss()
 
     def test_alert_accept(self):
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         alert.accept()
 
     def test_alert_dismiss(self):
@@ -107,51 +109,53 @@ class TestTabModalAlerts(BaseAlertTestCa
         # Restart the session to ensure we still find the formerly left-open dialog.
         self.marionette.delete_session()
         self.marionette.start_session()
 
         alert = self.marionette.switch_to_alert()
         alert.dismiss()
 
     def test_alert_text(self):
-        with self.assertRaises(NoAlertPresentException):
+        with self.assertRaises(errors.NoAlertPresentException):
             alert = self.marionette.switch_to_alert()
             alert.text
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         self.assertEqual(alert.text, "Marionette alert")
         alert.accept()
 
     def test_prompt_text(self):
-        with self.assertRaises(NoAlertPresentException):
+        with self.assertRaises(errors.NoAlertPresentException):
             alert = self.marionette.switch_to_alert()
             alert.text
         self.marionette.find_element(By.ID, "tab-modal-prompt").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         self.assertEqual(alert.text, "Marionette prompt")
         alert.accept()
 
     def test_confirm_text(self):
-        with self.assertRaises(NoAlertPresentException):
+        with self.assertRaises(errors.NoAlertPresentException):
             alert = self.marionette.switch_to_alert()
             alert.text
         self.marionette.find_element(By.ID, "tab-modal-confirm").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         self.assertEqual(alert.text, "Marionette confirm")
         alert.accept()
 
     def test_set_text_throws(self):
-        self.assertRaises(NoAlertPresentException, Alert(self.marionette).send_keys, "Foo")
+        with self.assertRaises(errors.NoAlertPresentException):
+            Alert(self.marionette).send_keys("Foo")
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
-        self.assertRaises(ElementNotInteractableException, alert.send_keys, "Foo")
+        with self.assertRaises(errors.ElementNotInteractableException):
+            alert.send_keys("Foo")
         alert.accept()
 
     def test_set_text_accept(self):
         self.marionette.find_element(By.ID, "tab-modal-prompt").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         alert.send_keys("Some text!")
         alert.accept()
@@ -189,41 +193,21 @@ class TestTabModalAlerts(BaseAlertTestCa
             """))
         self.marionette.navigate("about:blank")
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
         alert.accept()
         self.wait_for_condition(lambda mn: mn.get_url() == "about:blank")
 
-    @skip_if_e10s("Bug 1325044")
     def test_unrelated_command_when_alert_present(self):
-        click_handler = self.marionette.find_element(By.ID, "click-handler")
-        text = self.marionette.find_element(By.ID, "click-result").text
-        self.assertEqual(text, "")
-
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
-
-        # Commands succeed, but because the dialog blocks the event loop,
-        # our actions aren't reflected on the page.
-        text = self.marionette.find_element(By.ID, "click-result").text
-        self.assertEqual(text, "")
-        click_handler.click()
-        text = self.marionette.find_element(By.ID, "click-result").text
-        self.assertEqual(text, "")
-
-        alert = self.marionette.switch_to_alert()
-        alert.accept()
-
-        self.wait_for_alert_closed()
-
-        click_handler.click()
-        text = self.marionette.find_element(By.ID, "click-result").text
-        self.assertEqual(text, "result")
+        with self.assertRaises(errors.UnexpectedAlertOpen):
+            self.marionette.find_element(By.ID, "click-result")
 
 
 class TestModalAlerts(BaseAlertTestCase):
 
     def setUp(self):
         super(TestModalAlerts, self).setUp()
 
     def tearDown(self):
--- a/testing/marionette/test_assert.js
+++ b/testing/marionette/test_assert.js
@@ -28,16 +28,24 @@ add_test(function test_platforms() {
       raised = e;
     }
   }
   ok(raised instanceof UnsupportedOperationError);
 
   run_next_test();
 });
 
+add_test(function test_noUserPrompt() {
+  assert.noUserPrompt(null);
+  assert.noUserPrompt(undefined);
+  Assert.throws(() => assert.noUserPrompt({}), UnexpectedAlertOpenError);
+
+  run_next_test();
+});
+
 add_test(function test_defined() {
   assert.defined({});
   Assert.throws(() => assert.defined(undefined), InvalidArgumentError);
 
   run_next_test();
 });
 
 add_test(function test_number() {