Bug 1264259 - [marionette] Add support for unhandledPromptBehavior capability. draft
authorHenrik Skupin <mail@hskupin.info>
Sun, 10 Jun 2018 14:37:19 +0200
changeset 815109 574995da4d1eaa2e2a335482f45b2385b5c05e34
parent 814704 afdeb0288690f0acde2ba6bd008f860e1acdd026
push id115442
push userbmo:hskupin@gmail.com
push dateFri, 06 Jul 2018 19:55:54 +0000
bugs1264259
milestone63.0a1
Bug 1264259 - [marionette] Add support for unhandledPromptBehavior capability. The handling of user prompts for each of the commands is set by the current sessions user prompt handler. To fully support this feature this patch adds support for it including all available options which are "accept", "accept and notify", "dismiss", "dismiss and notify", and "ignore". MozReview-Commit-ID: IWuYM7QfZUv
testing/marionette/capabilities.js
testing/marionette/driver.js
testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
testing/marionette/harness/marionette_harness/tests/unit/test_unhandled_prompt_behavior.py
testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html
testing/marionette/test/unit/test_capabilities.js
testing/web-platform/meta/webdriver/tests/close_window/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/delete_cookie/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/element_send_keys/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/execute_async_script/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/execute_script/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/fullscreen_window/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/get_current_url/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/is_element_selected/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/minimize_window/user_prompts.py.ini
testing/web-platform/meta/webdriver/tests/set_window_rect/user_prompts.py.ini
--- a/testing/marionette/capabilities.js
+++ b/testing/marionette/capabilities.js
@@ -18,16 +18,17 @@ const {
 
 XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
 
 this.EXPORTED_SYMBOLS = [
   "Capabilities",
   "PageLoadStrategy",
   "Proxy",
   "Timeouts",
+  "UnhandledPromptBehavior",
 ];
 
 // Enable testing this module, as Services.appinfo.* is not available
 // in xpcshell tests.
 const appinfo = {name: "<missing>", version: "<missing>"};
 try { appinfo.name = Services.appinfo.name.toLowerCase(); } catch (e) {}
 try { appinfo.version = Services.appinfo.version; } catch (e) {}
 
@@ -352,30 +353,55 @@ class Proxy {
       socksVersion: this.socksVersion,
       proxyAutoconfigUrl: this.proxyAutoconfigUrl,
     });
   }
 
   toString() { return "[object Proxy]"; }
 }
 
+/**
+ * Enum of unhandled prompt behavior.
+ *
+ * @enum
+ */
+const UnhandledPromptBehavior = {
+  /** All simple dialogs encountered should be accepted. */
+  Accept: "accept",
+  /**
+   * All simple dialogs encountered should be accepted, and an error
+   * returned that the dialog was handled.
+   */
+  AcceptAndNotify: "accept and notify",
+  /** All simple dialogs encountered should be dismissed. */
+  Dismiss: "dismiss",
+  /**
+   * All simple dialogs encountered should be dismissed, and an error
+   * returned that the dialog was handled.
+   */
+  DismissAndNotify: "dismiss and notify",
+  /** All simple dialogs encountered should be left to the user to handle. */
+  Ignore: "ignore",
+};
+
 /** WebDriver session capabilities representation. */
 class Capabilities extends Map {
   /** @class */
   constructor() {
     super([
       // webdriver
       ["browserName", appinfo.name],
       ["browserVersion", appinfo.version],
       ["platformName", getWebDriverPlatformName()],
       ["platformVersion", Services.sysinfo.getProperty("version")],
+      ["acceptInsecureCerts", false],
       ["pageLoadStrategy", PageLoadStrategy.Normal],
-      ["acceptInsecureCerts", false],
+      ["proxy", new Proxy()],
       ["timeouts", new Timeouts()],
-      ["proxy", new Proxy()],
+      ["unhandledPromptBehavior", UnhandledPromptBehavior.DismissAndNotify],
 
       // features
       ["rotatable", appinfo.name == "B2G"],
 
       // proprietary
       ["moz:accessibilityChecks", false],
       ["moz:headless", Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless],
       ["moz:processID", Services.appinfo.processID],
@@ -465,16 +491,29 @@ class Capabilities extends Map {
           matched.set("proxy", proxy);
           break;
 
         case "timeouts":
           let timeouts = Timeouts.fromJSON(v);
           matched.set("timeouts", timeouts);
           break;
 
+        case "unhandledPromptBehavior":
+          assert.string(v,
+              pprint`Expected ${k} to be a string, got ${v}`);
+
+          if (Object.values(UnhandledPromptBehavior).includes(v)) {
+            matched.set("unhandledPromptBehavior", v);
+          } else {
+            throw new InvalidArgumentError(
+                `Unknown unhandled prompt behavior: ${v}`);
+          }
+
+          break;
+
         case "moz:accessibilityChecks":
           assert.boolean(v,
               pprint`Expected ${k} to be a boolean, got ${v}`);
           matched.set("moz:accessibilityChecks", v);
           break;
 
         case "moz:useNonSpecCompliantPointerOrigin":
           assert.boolean(v,
@@ -493,16 +532,17 @@ class Capabilities extends Map {
     return matched;
   }
 }
 
 this.Capabilities = Capabilities;
 this.PageLoadStrategy = PageLoadStrategy;
 this.Proxy = Proxy;
 this.Timeouts = Timeouts;
+this.UnhandledPromptBehavior = UnhandledPromptBehavior;
 
 function getWebDriverPlatformName() {
   let name = Services.sysinfo.getProperty("name");
 
   switch (name) {
     case "Windows_NT":
       return "windows";
 
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -15,16 +15,17 @@ ChromeUtils.import("chrome://marionette/
 const {
   browser,
   Context,
   WindowState,
 } = ChromeUtils.import("chrome://marionette/content/browser.js", {});
 const {
   Capabilities,
   Timeouts,
+  UnhandledPromptBehavior,
 } = ChromeUtils.import("chrome://marionette/content/capabilities.js", {});
 ChromeUtils.import("chrome://marionette/content/capture.js");
 const {
   CertificateOverrideManager,
   InsecureSweepingOverride,
 } = ChromeUtils.import("chrome://marionette/content/cert.js", {});
 ChromeUtils.import("chrome://marionette/content/cookie.js");
 const {
@@ -36,16 +37,17 @@ const {
   InsecureCertificateError,
   InvalidArgumentError,
   InvalidCookieDomainError,
   InvalidSelectorError,
   NoSuchAlertError,
   NoSuchFrameError,
   NoSuchWindowError,
   SessionNotCreatedError,
+  UnexpectedAlertOpenError,
   UnknownError,
   UnsupportedOperationError,
   WebDriverError,
 } = ChromeUtils.import("chrome://marionette/content/error.js", {});
 ChromeUtils.import("chrome://marionette/content/evaluate.js");
 const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js", {});
 ChromeUtils.import("chrome://marionette/content/interaction.js");
 ChromeUtils.import("chrome://marionette/content/l10n.js");
@@ -1063,17 +1065,17 @@ GeckoDriver.prototype.execute_ = async f
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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
   // readyState and send errors.
@@ -1105,17 +1107,17 @@ GeckoDriver.prototype.get = async functi
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getCurrentUrl = function() {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   return this.currentURL.toString();
 };
 
 /**
  * Gets the current title of the window.
  *
  * @return {string}
@@ -1123,17 +1125,17 @@ GeckoDriver.prototype.getCurrentUrl = fu
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getTitle = function() {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   return this.title;
 };
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function() {
   assert.open(this.getCurrentWindow());
 
@@ -1149,17 +1151,17 @@ GeckoDriver.prototype.getWindowType = fu
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getPageSource = async function() {
   const win = assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   switch (this.context) {
     case Context.Chrome:
       let s = new win.XMLSerializer();
       return s.serializeToString(win.document);
 
     case Context.Content:
       return this.listener.getPageSource();
@@ -1178,17 +1180,17 @@ GeckoDriver.prototype.getPageSource = as
  * @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.open(this.curBrowser);
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
     return;
   }
 
   let lastURL = this.currentURL;
   let goBack = this.listener.goBack({pageTimeout: this.timeouts.pageLoad});
@@ -1220,17 +1222,17 @@ GeckoDriver.prototype.goBack = async fun
  * @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.open(this.curBrowser);
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   // If there is no history, just return
   if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
     return;
   }
 
   let lastURL = this.currentURL;
   let goForward = this.listener.goForward(
@@ -1263,17 +1265,17 @@ GeckoDriver.prototype.goForward = async 
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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.
   this.curBrowser.pendingCommands.push(() => {
@@ -1406,17 +1408,17 @@ GeckoDriver.prototype.getChromeWindowHan
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getWindowRect = function() {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   return this.curBrowser.rect;
 };
 
 /**
  * Set the window position and size of the browser on the operating
  * system window manager.
  *
@@ -1444,17 +1446,17 @@ GeckoDriver.prototype.getWindowRect = fu
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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 => {
       win.addEventListener("resize", whenIdle(win, resolve), {once: true});
@@ -1672,17 +1674,17 @@ GeckoDriver.prototype.getActiveFrame = f
  *
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   await this.listener.switchToParentFrame();
 };
 
 /**
  * Switch to a given frame within the current window.
  *
  * @param {Object} element
@@ -1693,17 +1695,17 @@ GeckoDriver.prototype.switchToParentFram
  *
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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") {
     byFrame = WebElement.fromUUID(cmd.parameters.element, Context.Chrome);
@@ -1908,17 +1910,17 @@ GeckoDriver.prototype.singleTap = async 
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   let actions = cmd.parameters.actions;
   await this.listener.performActions({"actions": actions});
 };
 
 /**
  * Release all the keys and pointer buttons that are currently depressed.
  *
@@ -1927,17 +1929,17 @@ GeckoDriver.prototype.performActions = a
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   await this.listener.releaseActions();
 };
 
 /**
  * An action chain.
  *
  * @param {Object} value
@@ -1951,17 +1953,17 @@ GeckoDriver.prototype.releaseActions = a
  *     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) {
   const win = assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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();
@@ -1990,17 +1992,17 @@ GeckoDriver.prototype.actionChain = asyn
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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.
  *
@@ -2011,17 +2013,17 @@ GeckoDriver.prototype.multiAction = asyn
  *
  * @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) {
   const win = assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   let {using, value} = cmd.parameters;
   let startNode;
   if (typeof cmd.parameters.element != "undefined") {
     startNode = WebElement.fromUUID(cmd.parameters.element, this.context);
   }
 
   let opts = {
@@ -2110,17 +2112,17 @@ GeckoDriver.prototype.findElements = asy
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   return this.listener.getActiveElement();
 };
 
 /**
  * Send click event to element.
  *
  * @param {string} id
@@ -2132,17 +2134,17 @@ GeckoDriver.prototype.getActiveElement =
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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);
       await interaction.clickElement(el, this.a11yChecks);
@@ -2191,17 +2193,17 @@ GeckoDriver.prototype.clickElement = asy
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2232,17 +2234,17 @@ GeckoDriver.prototype.getElementAttribut
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2272,17 +2274,17 @@ GeckoDriver.prototype.getElementProperty
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2313,17 +2315,17 @@ GeckoDriver.prototype.getElementText = a
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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);
       return el.tagName.toLowerCase();
@@ -2351,17 +2353,17 @@ GeckoDriver.prototype.getElementTagName 
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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);
       return interaction.isElementDisplayed(el, this.a11yChecks);
@@ -2391,17 +2393,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) {
   const win = assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2431,17 +2433,17 @@ GeckoDriver.prototype.getElementValueOfC
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2470,17 +2472,17 @@ GeckoDriver.prototype.isElementEnabled =
  *     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) {
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2501,17 +2503,17 @@ GeckoDriver.prototype.isElementSelected 
  *     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) {
   const win = assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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);
       let rect = el.getBoundingClientRect();
@@ -2544,17 +2546,17 @@ GeckoDriver.prototype.getElementRect = a
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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:
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2582,17 +2584,17 @@ GeckoDriver.prototype.sendKeysToElement 
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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
       let el = this.curBrowser.seenEls.get(webEl);
@@ -2651,17 +2653,17 @@ GeckoDriver.prototype.switchToShadowRoot
  *     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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   let {protocol, hostname} = this.currentURL;
 
   const networkSchemes = ["ftp:", "http:", "https:"];
   if (!networkSchemes.includes(protocol)) {
     throw new InvalidCookieDomainError("Document is cookie-averse");
   }
 
@@ -2681,17 +2683,17 @@ GeckoDriver.prototype.addCookie = functi
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.getCookies = function() {
   assert.content(this.context);
   assert.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   let {hostname, pathname} = this.currentURL;
   return [...cookie.iter(hostname, pathname)];
 };
 
 /**
  * Delete all cookies that are visible to a document.
  *
@@ -2700,17 +2702,17 @@ GeckoDriver.prototype.getCookies = funct
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   let {hostname, pathname} = this.currentURL;
   for (let toDelete of cookie.iter(hostname, pathname)) {
     cookie.remove(toDelete);
   }
 };
 
 /**
@@ -2721,17 +2723,17 @@ GeckoDriver.prototype.deleteAllCookies =
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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);
     }
   }
@@ -2751,17 +2753,17 @@ GeckoDriver.prototype.deleteCookie = fun
  *
  * @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.open(this.getCurrentWindow(Context.Content));
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   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) {
       nwins += tabbrowser.tabs.length;
@@ -3004,17 +3006,17 @@ GeckoDriver.prototype.setScreenOrientati
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   if (WindowState.from(win.windowState) == WindowState.Fullscreen) {
     await exitFullscreen(win);
   }
 
   if (WindowState.from(win.windowState) != WindowState.Minimized) {
     await new Promise(resolve => {
       this.curBrowser.eventObserver.addEventListener("visibilitychange", resolve, {once: true});
@@ -3041,17 +3043,17 @@ GeckoDriver.prototype.minimizeWindow = a
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   switch (WindowState.from(win.windowState)) {
     case WindowState.Fullscreen:
       await exitFullscreen(win);
       break;
 
     case WindowState.Minimized:
       await restoreWindow(win, this.curBrowser.eventObserver);
@@ -3127,17 +3129,17 @@ GeckoDriver.prototype.maximizeWindow = a
  * @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.open(this.getCurrentWindow());
-  this._assertAndDismissModal();
+  this._handleUserPrompts();
 
   if (WindowState.from(win.windowState) == WindowState.Minimized) {
     await restoreWindow(win, this.curBrowser.eventObserver);
   }
 
   if (WindowState.from(win.windowState) != WindowState.Fullscreen) {
     await new Promise(resolve => {
       win.addEventListener("sizemodechange", resolve, {once: true});
@@ -3211,26 +3213,48 @@ GeckoDriver.prototype.sendKeysToDialog =
   // see toolkit/components/prompts/content/commonDialog.js
   let {loginTextbox} = this.dialog.ui;
   await interaction.sendKeysToElement(
       loginTextbox, cmd.parameters.text, this.a11yChecks);
 };
 
 GeckoDriver.prototype._checkIfAlertIsPresent = function() {
   if (!this.dialog || !this.dialog.ui) {
-    throw new NoSuchAlertError("No modal dialog is currently open");
+    throw new NoSuchAlertError();
   }
 };
 
-GeckoDriver.prototype._assertAndDismissModal = function() {
-  try {
-    assert.noUserPrompt(this.dialog);
-  } catch (e) {
-    this.dismissDialog();
-    throw e;
+GeckoDriver.prototype._handleUserPrompts = function() {
+  if (!this.dialog || !this.dialog.ui) {
+    return;
+  }
+
+  let behavior = this.capabilities.get("unhandledPromptBehavior");
+  switch (behavior) {
+    case UnhandledPromptBehavior.Accept:
+      this.acceptDialog();
+      break;
+
+    case UnhandledPromptBehavior.AcceptAndNotify:
+      this.acceptDialog();
+      throw new UnexpectedAlertOpenError();
+
+    case UnhandledPromptBehavior.Dismiss:
+      this.dismissDialog();
+      break;
+
+    case UnhandledPromptBehavior.DismissAndNotify:
+      this.dismissDialog();
+      throw new UnexpectedAlertOpenError();
+
+    case UnhandledPromptBehavior.Ignore:
+      throw new UnexpectedAlertOpenError();
+
+    default:
+      throw new TypeError(`Unknown unhandledPromptBehavior "${behavior}"`);
   }
 };
 
 /**
  * Enables or disables accepting new socket connections.
  *
  * By calling this method with `false` the server will not accept any
  * further connections, but existing connections will not be forcible
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
@@ -155,8 +155,38 @@ class TestCapabilityMatching(MarionetteT
 
     def test_timeouts(self):
         timeouts = {u"implicit": 123, u"pageLoad": 456, u"script": 789}
         caps = {"timeouts": timeouts}
         self.marionette.start_session(caps)
         self.assertIn("timeouts", self.marionette.session_capabilities)
         self.assertDictEqual(self.marionette.session_capabilities["timeouts"], timeouts)
         self.assertDictEqual(self.marionette._send_message("getTimeouts"), timeouts)
+
+    def test_unhandled_prompt_behavior(self):
+        behaviors = [
+            "accept",
+            "accept and notify",
+            "dismiss",
+            "dismiss and notify",
+            "ignore"
+        ]
+
+        for behavior in behaviors:
+            print("valid unhandled prompt behavior {}".format(behavior))
+            self.delete_session()
+            self.marionette.start_session({"unhandledPromptBehavior": behavior})
+            self.assertEqual(self.marionette.session_capabilities["unhandledPromptBehavior"],
+                             behavior)
+
+        # Default value
+        self.delete_session()
+        self.marionette.start_session()
+        self.assertEqual(self.marionette.session_capabilities["unhandledPromptBehavior"],
+                         "dismiss and notify")
+
+        # Invalid values
+        self.delete_session()
+        for behavior in [None, "", "ACCEPT", True, 42, {}, []]:
+            print("invalid unhandled prompt behavior {}".format(behavior))
+            with self.assertRaisesRegexp(SessionNotCreatedException, "InvalidArgumentError"):
+                self.marionette.start_session({"unhandledPromptBehavior": behavior})
+
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
@@ -10,40 +10,42 @@ from marionette_driver import errors
 from marionette_driver.marionette import Alert
 from marionette_driver.wait import Wait
 
 from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
 class BaseAlertTestCase(WindowManagerMixin, MarionetteTestCase):
 
+    @property
     def alert_present(self):
         try:
             Alert(self.marionette).text
             return True
         except errors.NoAlertPresentException:
             return False
 
     def wait_for_alert(self, timeout=None):
         Wait(self.marionette, timeout=timeout).until(
-            lambda _: self.alert_present())
+            lambda _: self.alert_present)
 
     def wait_for_alert_closed(self, timeout=None):
         Wait(self.marionette, timeout=timeout).until(
-            lambda _: not self.alert_present())
+            lambda _: not self.alert_present)
 
 
 class TestTabModalAlerts(BaseAlertTestCase):
 
     def setUp(self):
         super(TestTabModalAlerts, self).setUp()
         self.assertTrue(self.marionette.get_pref("prompts.tab_modal.enabled",
                         "Tab modal alerts should be enabled by default."))
 
-        self.marionette.navigate(self.marionette.absolute_url("test_tab_modal_dialogs.html"))
+        self.test_page = self.marionette.absolute_url("test_tab_modal_dialogs.html")
+        self.marionette.navigate(self.test_page)
 
     def tearDown(self):
         # Ensure to close a possible remaining tab modal dialog
         try:
             alert = self.marionette.switch_to_alert()
             alert.dismiss()
 
             self.wait_for_alert_closed()
@@ -178,17 +180,17 @@ class TestTabModalAlerts(BaseAlertTestCa
             self.marionette.find_element(By.ID, "click-result")
 
     def test_modal_is_dismissed_after_unexpected_alert(self):
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
         with self.assertRaises(errors.UnexpectedAlertOpen):
             self.marionette.find_element(By.ID, "click-result")
 
-        assert not self.alert_present()
+        assert not self.alert_present
 
 
 class TestModalAlerts(BaseAlertTestCase):
 
     def setUp(self):
         super(TestModalAlerts, self).setUp()
         self.marionette.set_pref("network.auth.non-web-content-triggered-resources-http-auth-allow",
                                  True)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_unhandled_prompt_behavior.py
@@ -0,0 +1,104 @@
+from __future__ import absolute_import
+
+from marionette_driver import errors
+from marionette_driver.marionette import Alert
+from marionette_driver.wait import Wait
+from marionette_harness import MarionetteTestCase, parameterized
+
+
+class TestUnhandledPromptBehavior(MarionetteTestCase):
+
+    def setUp(self):
+        super(TestUnhandledPromptBehavior, self).setUp()
+
+        self.marionette.delete_session()
+
+    def tearDown(self):
+        # Ensure to close a possible remaining tab modal dialog
+        try:
+            alert = self.marionette.switch_to_alert()
+            alert.dismiss()
+
+            Wait(self.marionette).until(lambda _: not self.alert_present)
+        except errors.NoAlertPresentException:
+            pass
+
+        super(TestUnhandledPromptBehavior, self).tearDown()
+
+    @property
+    def alert_present(self):
+        try:
+            Alert(self.marionette).text
+            return True
+        except errors.NoAlertPresentException:
+            return False
+
+    def perform_user_prompt_check(self, prompt_type, text, expected_result,
+                                  expected_close=True, expected_notify=True):
+        if prompt_type not in ["alert", "confirm", "prompt"]:
+            raise TypeError("Invalid dialog type: {}".format(prompt_type))
+
+        # No need to call resolve() because opening a prompt stops the script
+        self.marionette.execute_async_script("""
+            window.return_value = null;
+            window.return_value = window[arguments[0]](arguments[1]);
+        """, script_args=(prompt_type, text))
+
+        if expected_notify:
+            with self.assertRaises(errors.UnexpectedAlertOpen):
+                self.marionette.title
+            # Bug 1469752 - WebDriverError misses optional data property
+            # self.assertEqual(ex.data.text, text)
+        else:
+            self.marionette.title
+
+        self.assertEqual(self.alert_present, not expected_close)
+
+        prompt_result = self.marionette.execute_script(
+            "return window.return_value", new_sandbox=False)
+        self.assertEqual(prompt_result, expected_result)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", True)
+    @parameterized("prompt", "prompt", "")
+    def test_accept(self, prompt_type, result):
+        self.marionette.start_session({"unhandledPromptBehavior": "accept"})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result,
+                                       expected_notify=False)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", True)
+    @parameterized("prompt", "prompt", "")
+    def test_accept_and_notify(self, prompt_type, result):
+        self.marionette.start_session({"unhandledPromptBehavior": "accept and notify"})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", False)
+    @parameterized("prompt", "prompt", None)
+    def test_dismiss(self, prompt_type, result):
+        self.marionette.start_session({"unhandledPromptBehavior": "dismiss"})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result,
+                                       expected_notify=False)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", False)
+    @parameterized("prompt", "prompt", None)
+    def test_dismiss_and_notify(self, prompt_type, result):
+        self.marionette.start_session({"unhandledPromptBehavior": "dismiss and notify"})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", None)
+    @parameterized("prompt", "prompt", None)
+    def test_ignore(self, prompt_type, result):
+        self.marionette.start_session({"unhandledPromptBehavior": "ignore"})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result,
+                                       expected_close=False)
+
+    @parameterized("alert", "alert", None)
+    @parameterized("confirm", "confirm", False)
+    @parameterized("prompt", "prompt", None)
+    def test_default(self, prompt_type, result):
+        self.marionette.start_session({})
+        self.perform_user_prompt_check(prompt_type, "foo {}".format(prompt_type), result)
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -94,16 +94,19 @@ skip-if = true # Bug 925688
 [test_profile_management.py]
 skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921
 [test_quit_restart.py]
 skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921
 [test_context.py]
 
 [test_modal_dialogs.py]
 skip-if = appname == 'fennec' # Bug 1325738
+[test_unhandled_prompt_behavior.py]
+skip-if = appname == 'fennec' # Bug 1325738
+
 [test_key_actions.py]
 [test_legacy_mouse_action.py]
 skip-if = appname == 'fennec'
 [test_mouse_action.py]
 skip-if = appname == 'fennec'
 [test_teardown_context_preserved.py]
 [test_file_upload.py]
 skip-if = appname == 'fennec' || os == "win" # http://bugs.python.org/issue14574
--- a/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html
+++ b/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html
@@ -1,16 +1,16 @@
 <!-- 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/. -->
 
 <!DOCTYPE html>
 <html>
 <head>
-  <title>Marionette Test</title>
+  <title>Dialog Test</title>
   <script type="text/javascript">
     function handleAlert () {
       window.alert('Marionette alert');
     }
 
     function handleConfirm () {
       var alertAccepted = window.confirm('Marionette confirm');
       document.getElementById('confirm-result').innerHTML = alertAccepted;
--- a/testing/marionette/test/unit/test_capabilities.js
+++ b/testing/marionette/test/unit/test_capabilities.js
@@ -8,16 +8,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js", {});
 const {
   Capabilities,
   PageLoadStrategy,
   Proxy,
   Timeouts,
+  UnhandledPromptBehavior,
 } = ChromeUtils.import("chrome://marionette/content/capabilities.js", {});
 
 add_test(function test_Timeouts_ctor() {
   let ts = new Timeouts();
   equal(ts.implicit, 0);
   equal(ts.pageLoad, 300000);
   equal(ts.script, 30000);
 
@@ -361,16 +362,26 @@ add_test(function test_Proxy_fromJSON() 
   p.proxyType = "manual";
   p.noProxy = ["2001:db8::1"];
   let manual = {proxyType: "manual", "noProxy": ["[2001:db8::1]"]};
   deepEqual(p, Proxy.fromJSON(manual));
 
   run_next_test();
 });
 
+add_test(function test_UnhandledPromptBehavior() {
+  equal(UnhandledPromptBehavior.Accept, "accept");
+  equal(UnhandledPromptBehavior.AcceptAndNotify, "accept and notify");
+  equal(UnhandledPromptBehavior.Dismiss, "dismiss");
+  equal(UnhandledPromptBehavior.DismissAndNotify, "dismiss and notify");
+  equal(UnhandledPromptBehavior.Ignore, "ignore");
+
+  run_next_test();
+});
+
 add_test(function test_Capabilities_ctor() {
   let caps = new Capabilities();
   ok(caps.has("browserName"));
   ok(caps.has("browserVersion"));
   ok(caps.has("platformName"));
   ok(["linux", "mac", "windows", "android"].includes(caps.get("platformName")));
   ok(caps.has("platformVersion"));
   equal(PageLoadStrategy.Normal, caps.get("pageLoadStrategy"));
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/close_window/user_prompts.py.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/delete_cookie/user_prompts.py.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/element_send_keys/user_prompts.py.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/execute_async_script/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/execute_async_script/user_prompts.py.ini
@@ -1,38 +1,11 @@
 [user_prompts.py]
   disabled:
     if webrender: bug 1425588
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-prompt\]]
-    expected: FAIL
-
   [test_handle_prompt_twice[capabilities0-alert\]]
     expected: FAIL
     disabled: Bug 1459118
 
   [test_handle_prompt_twice[capabilities0-confirm\]]
     expected: FAIL
     disabled: Bug 1459118
 
--- a/testing/web-platform/meta/webdriver/tests/execute_script/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/execute_script/user_prompts.py.ini
@@ -1,38 +1,11 @@
 [user_prompts.py]
   disabled:
     if webrender: bug 1425588
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_ignore[capabilities0-prompt\]]
-    expected: FAIL
-
   [test_handle_prompt_twice[capabilities0-alert\]]
     expected: FAIL
     disabled: Bug 1459118
 
   [test_handle_prompt_twice[capabilities0-confirm\]]
     expected: FAIL
     disabled: Bug 1459118
 
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/fullscreen_window/user_prompts.py.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/get_current_url/user_prompts.py.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini
@@ -1,20 +1,3 @@
 [user_prompts.py]
   disabled:
     if webrender: bug 1425588
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini
@@ -1,20 +1,3 @@
 [user_prompts.py]
   disabled:
     if webrender: bug 1425588
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini
@@ -1,20 +1,3 @@
 [user_prompts.py]
   disabled:
     if webrender: bug 1425588
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini
@@ -1,11 +1,3 @@
 [user_prompts.py]
   disabled:
     if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): wpt-sync Bug 1446953
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/is_element_selected/user_prompts.py.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_dismiss[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_dismiss[capabilities0-prompt\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
--- a/testing/web-platform/meta/webdriver/tests/minimize_window/user_prompts.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/minimize_window/user_prompts.py.ini
@@ -1,12 +1,3 @@
 [user_prompts.py]
   disabled:
     if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): wpt-sync Bug 1449780
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/set_window_rect/user_prompts.py.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[user_prompts.py]
-  [test_handle_prompt_accept[capabilities0-alert\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-confirm\]]
-    expected: FAIL
-
-  [test_handle_prompt_accept[capabilities0-prompt\]]
-    expected: FAIL
-