Bug 1321516 - Add preliminary support for unexpected alerts draft
authorAndreas Tolfsen <ato@mozilla.com>
Thu, 20 Apr 2017 18:00:46 +0100
changeset 567108 8f3bfd73aaa9db98a874a587ee0e8efdd88d8b29
parent 566881 73752931e273091185e1e4b5231c28beed657cc8
child 625524 1b1bfa44e51115aebe7e322fc3f8146458168c0a
push id55443
push userbmo:ato@mozilla.com
push dateMon, 24 Apr 2017 12:20:06 +0000
bugs1321516, 1264259
milestone55.0a1
Bug 1321516 - 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: FCjbtwTVj9B
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 {UnexpectedAlertOpen}
+ *     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
@@ -970,16 +970,17 @@ GeckoDriver.prototype.executeJSScript = 
  * 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());
+  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.
@@ -1006,30 +1007,32 @@ GeckoDriver.prototype.get = function* (c
  * 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());
+  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. */
 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();
@@ -1041,37 +1044,37 @@ GeckoDriver.prototype.getTitle = functio
 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. */
 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;
+      return s.serializeToString(win.document);
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getPageSource();
-      break;
+      return this.listener.getPageSource();
   }
 };
 
 /**
  * Cause the browser to traverse one step backward in the joint history
  * of the current browsing context.
  */
 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;
@@ -1101,16 +1104,17 @@ GeckoDriver.prototype.goBack = function*
 
 /**
  * Cause the browser to traverse one step forward in the joint history
  * of the current browsing context.
  */
 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;
@@ -1139,16 +1143,17 @@ GeckoDriver.prototype.goForward = functi
 };
 
 /**
  * Causes the browser to reload the page in in current top-level browsing context.
  */
 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) {
@@ -1261,17 +1266,18 @@ GeckoDriver.prototype.getChromeWindowHan
  * 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.
  */
 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,
   };
 };
 
@@ -1289,19 +1295,19 @@ GeckoDriver.prototype.getWindowRect = fu
  *     moved to.
  *
  * @return {Object.<string, number>}
  *     Object with |x| and |y| coordinates
  *     and |width| and |height| dimensions
  *
  */
 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 +1452,34 @@ 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) {
+GeckoDriver.prototype.switchToParentFrame = function* (cmd, resp) {
   assert.window(this.getCurrentWindow());
-
-  let res = yield this.listener.switchToParentFrame();
+  assert.noUserPrompt(this.dialog);
+  return 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());
+  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();
 
@@ -1680,18 +1687,19 @@ 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.
  */
-GeckoDriver.prototype.performActions = function(cmd, resp) {
+GeckoDriver.prototype.performActions = function (cmd, resp) {
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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});
@@ -1772,18 +1780,19 @@ 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());
+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,
   };
@@ -1855,18 +1864,19 @@ GeckoDriver.prototype.findElements = fun
           cmd.parameters.using,
           cmd.parameters.value,
           opts);
       break;
   }
 };
 
 /** Return the active element on the page. */
-GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
+GeckoDriver.prototype.getActiveElement = function* (cmd, resp) {
   assert.window(this.getCurrentWindow());
+  assert.noUserPrompt(this.dialog);
 
   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();
@@ -1875,18 +1885,19 @@ 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());
+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;
@@ -1908,25 +1919,25 @@ 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.
  */
-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;
   }
 };
@@ -1937,42 +1948,44 @@ 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.
  */
-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;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementProperty(id, name);
+      resp.body.value = this.listener.getElementProperty(id, name);
       break;
   }
 };
 
 /**
  * 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());
+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 = [];
@@ -1987,166 +2000,171 @@ 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());
+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;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementTagName(id);
+      resp.body.value = this.listener.getElementTagName(id);
       break;
   }
 };
 
 /**
  * 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());
+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);
+      resp.body.value = interaction.isElementDisplayed(el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementDisplayed(id);
+      resp.body.value = this.listener.isElementDisplayed(id);
       break;
   }
 };
 
 /**
  * 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());
+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);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.getElementValueOfCssProperty(id, prop);
+      resp.body.value = this.listener.getElementValueOfCssProperty(id, prop);
       break;
   }
 };
 
 /**
  * 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());
+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);
+      resp.body.value = interaction.isElementEnabled(el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementEnabled(id);
-      break;
+      resp.body.value = this.listener.isElementEnabled(id);
   }
-},
+};
 
 /**
  * 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());
+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(
+      resp.body.value = interaction.isElementSelected(
           el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
-      resp.body.value = yield this.listener.isElementSelected(id);
+      resp.body.value = this.listener.isElementSelected(id);
       break;
   }
 };
 
-GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
+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 = {
         x: rect.x + win.pageXOffset,
         y: rect.y + win.pageYOffset,
         width: rect.width,
         height: rect.height
       };
       break;
 
     case Context.CONTENT:
-      resp.body = yield this.listener.getElementRect(id);
+      resp.body = this.listener.getElementRect(id);
       break;
   }
 };
 
 /**
  * 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());
+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);
@@ -2154,32 +2172,33 @@ GeckoDriver.prototype.sendKeysToElement 
 
     case Context.CONTENT:
       yield this.listener.sendKeysToElement(id, text);
       break;
   }
 };
 
 /** Sets the test name.  The test name is used for logging purposes. */
-GeckoDriver.prototype.setTestName = function*(cmd, resp) {
+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());
+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 +2214,29 @@ GeckoDriver.prototype.clearElement = fun
   }
 };
 
 /**
  * Switch to shadow root of the given host element.
  *
  * @param {string} id element id.
  */
-GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
+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) {
+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,
@@ -2235,27 +2254,29 @@ 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) {
+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) {
+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,
@@ -2264,19 +2285,20 @@ 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) {
+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,
@@ -2297,16 +2319,17 @@ GeckoDriver.prototype.deleteCookie = fun
  * 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());
+  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.
@@ -2599,17 +2622,18 @@ GeckoDriver.prototype.setScreenOrientati
 /**
  * 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 = assert.window(this.getCurrentWindow());
+  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 {
@@ -487,12 +495,13 @@ const STATUSES = new Map([
   ["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],
   ["unknown command", UnknownCommandError],
+  ["unexpected alert open", UnexpectedAlertOpenError],
   ["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() {