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
--- 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):