Bug 1333014 - Align element interaction errors with spec; r?whimboo draft
authorAndreas Tolfsen <ato@mozilla.com>
Fri, 03 Feb 2017 19:30:13 +0000
changeset 479458 188a8f00ffc1c26091d9ede2284536ccfb8ae7d1
parent 479457 2561453770f14c8b8f6ee9056fd656231133e482
child 479459 8f80f1b9bfbcaccd9ac8293fc4cc2f8d5e30fcdb
push id44264
push userbmo:ato@mozilla.com
push dateMon, 06 Feb 2017 19:13:44 +0000
reviewerswhimboo
bugs1333014
milestone54.0a1
Bug 1333014 - Align element interaction errors with spec; r?whimboo This renames the ElementNotVisibleError to ElementNotInteractableError, and adds a new ElementClickInterceptedError. MozReview-Commit-ID: 6cjVghUCvyv
testing/marionette/driver.js
testing/marionette/error.js
testing/marionette/event.js
testing/marionette/listener.js
testing/marionette/test_error.js
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -2496,17 +2496,18 @@ GeckoDriver.prototype.getTextFromDialog 
  * an element not visible error is returned.
  */
 GeckoDriver.prototype.sendKeysToDialog = function (cmd, resp) {
   this._checkIfAlertIsPresent();
 
   // see toolkit/components/prompts/content/commonDialog.js
   let {loginContainer, loginTextbox} = this.dialog.ui;
   if (loginContainer.hidden) {
-    throw new ElementNotVisibleError("This prompt does not accept text input");
+    throw new ElementNotInteractableError(
+        "This prompt does not accept text input");
   }
 
   let win = this.dialog.window ? this.dialog.window : this.getCurrentWindow();
   event.sendKeysToElement(
       cmd.parameters.value,
       loginTextbox,
       {ignoreVisibility: true},
       win);
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -2,18 +2,19 @@
  * 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/. */
 
 "use strict";
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 const ERRORS = new Set([
+  "ElementClickInterceptedError",
   "ElementNotAccessibleError",
-  "ElementNotVisibleError",
+  "ElementNotInteractableError",
   "InsecureCertificateError",
   "InvalidArgumentError",
   "InvalidElementStateError",
   "InvalidSelectorError",
   "InvalidSessionIdError",
   "JavaScriptError",
   "NoAlertOpenError",
   "NoSuchElementError",
@@ -216,22 +217,50 @@ WebDriverError.prototype = Object.create
 
 this.ElementNotAccessibleError = function (msg) {
   WebDriverError.call(this, msg);
   this.name = "ElementNotAccessibleError";
   this.status = "element not accessible";
 };
 ElementNotAccessibleError.prototype = Object.create(WebDriverError.prototype);
 
-this.ElementNotVisibleError = function (msg) {
+/**
+ * The click could not be completed because the element receiving the
+ * events is not the same as the element that was requested clicked.
+ *
+ * @param {Element=} obscuredEl
+ *     Obscured element.
+ * @param {Map.<string, number>=} coords
+ *     Point to click.
+ */
+this.ElementClickInterceptedError =
+    function (obscuredEl = undefined, coords = undefined) {
+  let msg;
+
+  if (obscuredEl && coords) {
+    let doc = obscuredEl.ownerDocument;
+    let overlayingEl = doc.elementFromPoint(coords.x, coords.y);
+    msg = error.pprint`Element ${obscuredEl} is not clickable ` +
+      `at point (${coords.x}, ${coords.y}) ` +
+      error.pprint`because another element ${overlayingEl} ` +
+      `obscures it`;
+  }
+
   WebDriverError.call(this, msg);
-  this.name = "ElementNotVisibleError";
-  this.status = "element not visible";
+  this.name = "ElementClickInterceptedError";
+  this.status = "element click intercepted";
 };
-ElementNotVisibleError.prototype = Object.create(WebDriverError.prototype);
+ElementClickInterceptedError.prototype = Object.create(WebDriverError.prototype);
+
+this.ElementNotInteractableError = function (msg) {
+  WebDriverError.call(this, msg);
+  this.name = "ElementNotInteractableError";
+  this.status = "element not interactable";
+};
+ElementNotInteractableError.prototype = Object.create(WebDriverError.prototype);
 
 this.InsecureCertificateError = function (msg) {
   WebDriverError.call(this, msg);
   this.name = "InsecureCertificateError";
   this.status = "insecure certificate";
 };
 InsecureCertificateError.prototype = Object.create(WebDriverError.prototype);
 
--- a/testing/marionette/event.js
+++ b/testing/marionette/event.js
@@ -1291,17 +1291,17 @@ event.sendKeysToElement = function (
 
     let value = keySequence.join("");
     for (let i = 0; i < value.length; i++) {
       let c = value.charAt(i);
       event.sendSingleKey(c, modifiers, window);
     }
 
   } else {
-    throw new ElementNotVisibleError("Element is not visible");
+    throw new ElementNotInteractable("Element is not visible");
   }
 };
 
 event.sendEvent = function (eventType, el, modifiers = {}, opts = {}) {
   opts.canBubble = opts.canBubble || true;
 
   let doc = el.ownerDocument || el.document;
   let ev = doc.createEvent("Event");
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -639,17 +639,17 @@ function emitTouchEvent(type, touch) {
 /**
  * Function that perform a single tap
  */
 function singleTap(id, corx, cory) {
   let el = seenEls.get(id, curContainer);
   // after this block, the element will be scrolled into view
   let visible = element.isVisible(el, corx, cory);
   if (!visible) {
-    throw new ElementNotVisibleError("Element is not currently visible and may not be manipulated");
+    throw new ElementNotInteractable("Element is not currently visible and may not be manipulated");
   }
 
   let a11y = accessibility.get(capabilities.get("moz:accessibilityChecks"));
   return a11y.getAccessible(el, true).then(acc => {
     a11y.assertVisible(acc, el, visible);
     a11y.assertActionable(acc, el);
     if (!curContainer.frame.document.createTouch) {
       legacyactions.mouseEventsOnly = true;
--- a/testing/marionette/test_error.js
+++ b/testing/marionette/test_error.js
@@ -144,21 +144,21 @@ add_test(function test_ElementNotAccessi
   equal("ElementNotAccessibleError", err.name);
   equal("foo", err.message);
   equal("element not accessible", err.status);
   equal(WebDriverError.prototype.toString(), Object.getPrototypeOf(err).toString());
 
   run_next_test();
 });
 
-add_test(function test_ElementNotVisibleError() {
-  let err = new ElementNotVisibleError("foo");
-  equal("ElementNotVisibleError", err.name);
+add_test(function test_ElementNotInteractableError() {
+  let err = new ElementNotInteractableError("foo");
+  equal("ElementNotInteractableError", err.name);
   equal("foo", err.message);
-  equal("element not visible", err.status);
+  equal("element not interactable", err.status);
   equal(WebDriverError.prototype.toString(), Object.getPrototypeOf(err).toString());
 
   run_next_test();
 });
 
 add_test(function test_InvalidArgumentError() {
   let err = new InvalidArgumentError("foo");
   equal("InvalidArgumentError", err.name);