Bug 1317386 - Scroll element into view at the bottom. r=automatedtester, a=test-only
authorAndreas Tolfsen <ato@mozilla.com>
Mon, 14 Nov 2016 21:06:50 +0000
changeset 356709 406d6147e9dff6bedb622f1fc6f298b5fc324f4e
parent 356708 08a24b71cfd864cda7a88eb9f524f2b5461aed0a
child 356710 30ffa3343e2e80e178d3f82930fd41a4baa3655c
push id6605
push userryanvm@gmail.com
push dateWed, 23 Nov 2016 23:45:22 +0000
treeherdermozilla-beta@f8cd956e52d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester, test-only
bugs1317386
milestone51.0
Bug 1317386 - Scroll element into view at the bottom. r=automatedtester, a=test-only 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"],