Bug 1317386 - Scroll element into view at the bottom; r?automatedtester draft
authorAndreas Tolfsen <ato@mozilla.com>
Mon, 14 Nov 2016 21:06:50 +0000
changeset 441071 322f093a70848489c6f5e82d9510655ae9793852
parent 441054 28e2a6dde76ab6ad4464a3662df1bd57af04398a
child 441072 0eead2f40ec0ff4f80a4b33defb68eb64357c9dc
push id36351
push userbmo:ato@mozilla.com
push dateFri, 18 Nov 2016 10:30:51 +0000
reviewersautomatedtester
bugs1317386
milestone53.0a1
Bug 1317386 - Scroll element into view at the bottom; r?automatedtester When scrolling an element into view using `Element.scrollIntoView`, use the `{block: "end", inline: "nearest"}` scroll position arguments, which are equivalent to `Element.scrollIntoView(false)`. This is what other WebDriver implementations have used for a while, and we meant to change to this sooner. This ensures that the element appears at the bottom of the viewport rather than the top, where overlaying menus with fixed style position may more frequently appear. In the future we might consider replacing this with `{block: "center"}` which is specified in the CSSOM specification, but not yet implemented in any browsers. This implements https://github.com/w3c/webdriver/pull/440, which should fix https://github.com/mozilla/geckodriver/issues/327. MozReview-Commit-ID: BRMupP4fM89
testing/marionette/element.js
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -769,17 +769,17 @@ element.toJson = function(obj, seenEls) 
 };
 
 /**
  * Check if the element is detached from the current frame as well as
  * the optional shadow root (when inside a Shadow DOM context).
  *
  * @param {nsIDOMElement} el
  *     Element to be checked.
- * @param nsIDOMWindow frame
+ * @param {nsIDOMWindow} frame
  *     Window object that contains the element or the current host
  *     of the shadow root.
  * @param {ShadowRoot=} shadowRoot
  *     An optional shadow root containing an element.
  *
  * @return {boolean}
  *     Flag indicating that the element is disconnected.
  */
@@ -905,22 +905,18 @@ element.isVisible = function(el, x = und
     return false;
   }
 
   if (el.tagName.toLowerCase() == "body") {
     return true;
   }
 
   if (!element.inViewport(el, x, y)) {
-    if (el.scrollIntoView) {
-      el.scrollIntoView({block: "start", inline: "nearest"});
-      if (!element.inViewport(el)) {
-        return false;
-      }
-    } else {
+    element.scrollIntoView(el);
+    if (!element.inViewport(el)) {
       return false;
     }
   }
   return true;
 };
 
 element.isInteractable = function(el) {
   return element.isPointerInteractable(el) ||
@@ -998,16 +994,28 @@ element.getInteractableElementTree = fun
 };
 
 // TODO(ato): Not implemented.
 // In fact, it's not defined in the spec.
 element.isKeyboardInteractable = function(el) {
   return true;
 };
 
+/**
+ * Attempts to scroll into view |el|.
+ *
+ * @param {DOMElement} el
+ *     Element to scroll into view.
+ */
+element.scrollIntoView = function(el) {
+  if (el.scrollIntoView) {
+    el.scrollIntoView({block: "end", inline: "nearest", behavior: "instant"});
+  }
+};
+
 element.isXULElement = function(el) {
   let ns = atom.getElementAttribute(el, "namespaceURI");
   return ns.indexOf("there.is.only.xul") >= 0;
 };
 
 const boolEls = {
   audio: ["autoplay", "controls", "loop", "muted"],
   button: ["autofocus", "disabled", "formnovalidate"],