Bug 1406505 - Fix element.getContainer() to return button as container. draft
authorHenrik Skupin <mail@hskupin.info>
Fri, 20 Oct 2017 17:52:03 +0200
changeset 690107 2d0c817035a6941f2fabd6e05cd34d08685b0adc
parent 687186 aa958b29c149a67fce772f8473e9586e71fbdb46
child 690108 9a6b182697fc7c01948fd17593ffdacb9605e1b2
child 690245 d0e5bea2dfbb514c685c8502bf51a298caebc827
push id87214
push userbmo:hskupin@gmail.com
push dateWed, 01 Nov 2017 16:49:56 +0000
bugs1406505, 1089326
milestone58.0a1
Bug 1406505 - Fix element.getContainer() to return button as container. Because as long as bug 1089326 is not fixed child nodes of <button> are not part of the element tree. As such the button has to be returned as container for any of those nodes. MozReview-Commit-ID: Jq6B9Kn7VAf
testing/marionette/element.js
testing/marionette/harness/marionette_harness/tests/unit/test_click.py
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -843,35 +843,38 @@ element.inViewport = function(el, x = un
  *
  * @param {Element} el
  *     Element to get the container of.
  *
  * @return {Element}
  *     Container element of |el|.
  */
 element.getContainer = function(el) {
-  if (el.localName != "option") {
-    return el;
-  }
 
-  function validContext(ctx) {
-    return ctx.localName == "datalist" || ctx.localName == "select";
+  function findAncestralElement(startNode, validAncestors) {
+    let node = startNode;
+    while (node.parentNode) {
+      node = node.parentNode;
+      if (validAncestors.includes(node.localName)) {
+        return node;
+      }
+    }
+
+    return startNode;
   }
 
-  // does <option> have a valid context,
+  // Does <option> have a valid context,
   // meaning is it a child of <datalist> or <select>?
-  let parent = el;
-  while (parent.parentNode && !validContext(parent)) {
-    parent = parent.parentNode;
+  if (el.localName === "option") {
+    return findAncestralElement(el, ["datalist", "select"]);
   }
 
-  if (!validContext(parent)) {
-    return el;
-  }
-  return parent;
+  // Child nodes of button will not be part of the element tree for
+  // elementsFromPoint until bug 1089326 is fixed.
+  return findAncestralElement(el, ["button"]);
 };
 
 /**
  * An element is in view if it is a member of its own pointer-interactable
  * paint tree.
  *
  * This means an element is considered to be in view, but not necessarily
  * pointer-interactable, if it is found somewhere in the
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
@@ -222,25 +222,34 @@ class TestClick(TestLegacyClick):
 
         self.marionette.find_element(By.TAG_NAME, "div").click()
 
     def test_input_file(self):
         self.marionette.navigate(inline("<input type=file>"))
         with self.assertRaises(errors.InvalidArgumentException):
             self.marionette.find_element(By.TAG_NAME, "input").click()
 
-    def test_container_element(self):
+    def test_container_for_select(self):
         self.marionette.navigate(inline("""
             <select>
               <option>foo</option>
             </select>"""))
         option = self.marionette.find_element(By.TAG_NAME, "option")
         option.click()
         self.assertTrue(option.get_property("selected"))
 
+    def test_container_for_button(self):
+        self.marionette.navigate(inline("""
+          <button onclick="window.clicked = true;">
+            <span><em>foo</em></span>
+          </button>"""))
+        span = self.marionette.find_element(By.TAG_NAME, "span")
+        span.click()
+        self.assertTrue(self.marionette.execute_script("return window.clicked", sandbox=None))
+
     def test_container_element_outside_view(self):
         self.marionette.navigate(inline("""
             <select style="margin-top: 100vh">
               <option>foo</option>
             </select>"""))
         option = self.marionette.find_element(By.TAG_NAME, "option")
         option.click()
         self.assertTrue(option.get_property("selected"))