Bug 1321516 - Add preliminary support for unexpected alerts draft
authorAndreas Tolfsen <ato@mozilla.com>
Thu, 20 Apr 2017 18:00:46 +0100
changeset 567227 c1399de423abf7b853dfc3af954f473af669fc62
parent 567226 2d8e7cce45051687cb18ee0d57d58d5ee6c774e8
child 625555 4d977936707e24b7ab4db700fab9ef80a554d52c
push id55475
push userbmo:ato@mozilla.com
push dateMon, 24 Apr 2017 14:23:53 +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: 2805ax3Y9xG
testing/marionette/driver.js
testing/marionette/error.js
testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -1773,17 +1773,18 @@ 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());
+  const win = assert.window(this.getCurrentWindow());
+  this._assertNoUserPrompt();
 
   let strategy = cmd.parameters.using;
   let expr = cmd.parameters.value;
   let opts = {
     startNode: cmd.parameters.element,
     timeout: this.timeouts.implicit,
     all: false,
   };
@@ -1876,19 +1877,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());
-
-  let id = cmd.parameters.id;
+  const win = assert.window(this.getCurrentWindow());
+  const id = cmd.parameters.id;
+  this._assertNoUserPrompt();
 
   switch (this.context) {
     case Context.CHROME:
       let el = this.curBrowser.seenEls.get(id, {frame: win});
       yield interaction.clickElement(el, this.a11yChecks);
       break;
 
     case Context.CONTENT:
@@ -2679,16 +2680,22 @@ GeckoDriver.prototype.sendKeysToDialog =
 
   event.sendKeysToElement(
       cmd.parameters.text,
       loginTextbox,
       {ignoreVisibility: true},
       this.dialog.window ? this.dialog.window : win);
 };
 
+GeckoDriver.prototype._assertNoUserPrompt = function () {
+  if (this.dialog) {
+    throw new UnexpectedAlertOpenError();
+  }
+};
+
 GeckoDriver.prototype._checkIfAlertIsPresent = function () {
   if (!this.dialog || !this.dialog.ui) {
     throw new NoAlertOpenError("No modal dialog is currently open");
   }
 };
 
 /**
  * Enables or disables accepting new socket connections.
--- 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",
@@ -458,16 +459,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 {
@@ -500,12 +508,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):