Bug 1143071 - Searching anonymous elements has to use the documentElement as default start node. draft
authorHenrik Skupin <mail@hskupin.info>
Fri, 02 Dec 2016 17:36:52 +0100
changeset 449832 3c957a33d6bde981155b8d88bae22ceb674bfd00
parent 449801 7652a58efa46f1c57c94bba26efc5d53b6184e83
child 539603 42606bdf0c6adeabaf1cae65ef5c4e564f0f5446
push id38689
push userbmo:hskupin@gmail.com
push dateThu, 15 Dec 2016 07:28:14 +0000
bugs1143071
milestone53.0a1
Bug 1143071 - Searching anonymous elements has to use the documentElement as default start node. MozReview-Commit-ID: 90zTSulITcR
testing/marionette/chrome/test_anonymous_content.xul
testing/marionette/element.js
testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py
--- a/testing/marionette/chrome/test_anonymous_content.xul
+++ b/testing/marionette/chrome/test_anonymous_content.xul
@@ -1,35 +1,37 @@
 <?xml version="1.0"?>
 <!-- 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/. -->
 
-<!DOCTYPE window [
+<!DOCTYPE dialog [
 ]>
-<window id="winTest" title="Title Test" windowtype="Test Type"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <dialog id="dia"
-                xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<dialog id="testDialogAnonymousNode"
+          buttons="accept, cancel"
+          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
   <bindings id="testBindings" xmlns="http://www.mozilla.org/xbl"
-      xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+            xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     <binding id="framebox">
       <content orient="vertical" mousethrough="never">
         <xul:browser anonid="content" id="browser" flex="1"
-                   context="contentAreaContextMenu"
-                   src="test.xul"
-                   type="content"/>
+                     context="contentAreaContextMenu"
+                     src="test.xul"
+                     type="content"/>
       </content>
     </binding>
 
     <binding id="iframebox">
       <content>
         <xul:box>
           <xul:iframe anonid="iframe" src="chrome://marionette/content/test.xul"></xul:iframe>
         </xul:box>
       </content>
     </binding>
   </bindings>
+
   <hbox id="testAnonymousContentBox"/>
   <hbox id="container" style="-moz-binding: url('#testBindings');"/>
   <hbox id="container2" style="-moz-binding: url('#iframebox');"/>
-  </dialog>
-</window>
+
+</dialog>
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -272,17 +272,35 @@ element.find = function (container, stra
       }
       resolve(foundEls[0]);
     }, reject);
   });
 };
 
 function find_(container, strategy, selector, searchFn, opts) {
   let rootNode = container.shadowRoot || container.frame.document;
-  let startNode = opts.startNode || rootNode;
+  let startNode;
+
+  if (opts.startNode) {
+    startNode = opts.startNode;
+  } else {
+    switch (strategy) {
+      // For anonymous nodes the start node needs to be of type DOMElement, which
+      // will refer to :root in case of a DOMDocument.
+      case element.Strategy.Anon:
+      case element.Strategy.AnonAttribute:
+        if (rootNode instanceof Ci.nsIDOMDocument) {
+          startNode = rootNode.documentElement;
+        }
+        break;
+
+      default:
+        startNode = rootNode;
+    }
+  }
 
   let res;
   try {
     res = searchFn(strategy, selector, rootNode, startNode);
   } catch (e) {
     throw new InvalidSelectorError(
         `Given ${strategy} expression "${selector}" is invalid: ${e}`);
   }
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py
@@ -1,72 +1,93 @@
 # 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 unittest import skip
 
 from marionette_driver.by import By
 from marionette_driver.errors import NoSuchElementException
-from marionette_driver.expected import element_present
 from marionette_driver.marionette import HTMLElement
-from marionette_driver.wait import Wait
 
 from marionette_harness import MarionetteTestCase, WindowManagerMixin
 
 
-class TestAnonymousContent(WindowManagerMixin, MarionetteTestCase):
+class TestAnonymousNodes(WindowManagerMixin, MarionetteTestCase):
 
     def setUp(self):
-        super(TestAnonymousContent, self).setUp()
+        super(TestAnonymousNodes, self).setUp()
         self.marionette.set_context("chrome")
 
         def open_window_with_js():
             self.marionette.execute_script("""
               window.open('chrome://marionette/content/test_anonymous_content.xul',
                           'foo', 'chrome,centerscreen');
             """)
 
         new_window = self.open_window(trigger=open_window_with_js)
         self.marionette.switch_to_window(new_window)
-        self.assertNotEqual(self.marionette.current_chrome_window_handle, self.start_window)
 
     def tearDown(self):
         self.close_all_windows()
 
+        super(TestAnonymousNodes, self).tearDown()
+
     def test_switch_to_anonymous_frame(self):
         self.marionette.find_element(By.ID, "testAnonymousContentBox")
         anon_browser_el = self.marionette.find_element(By.ID, "browser")
         self.assertTrue("test_anonymous_content.xul" in self.marionette.get_url())
         self.marionette.switch_to_frame(anon_browser_el)
         self.assertTrue("test.xul" in self.marionette.get_url())
         self.marionette.find_element(By.ID, "testXulBox")
-        self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "testAnonymousContentBox")
+        self.assertRaises(NoSuchElementException,
+                          self.marionette.find_element, By.ID, "testAnonymousContentBox")
 
     @skip("Bug 1311657 - Opened chrome window cannot be closed after call to switch_to_frame")
     def test_switch_to_anonymous_iframe(self):
         self.marionette.find_element(By.ID, "testAnonymousContentBox")
         el = self.marionette.find_element(By.ID, "container2")
         anon_iframe_el = el.find_element(By.ANON_ATTRIBUTE, {"anonid": "iframe"})
         self.marionette.switch_to_frame(anon_iframe_el)
         self.assertTrue("test.xul" in self.marionette.get_url())
         self.marionette.find_element(By.ID, "testXulBox")
         self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID,
                           "testAnonymousContentBox")
 
     def test_find_anonymous_element_by_attribute(self):
-        el = Wait(self.marionette).until(element_present(By.ID, "dia"))
-        self.assertEquals(HTMLElement, type(el.find_element(By.ANON_ATTRIBUTE, {"anonid": "buttons"})))
-        self.assertEquals(1, len(el.find_elements(By.ANON_ATTRIBUTE, {"anonid": "buttons"})))
+        accept_button = (By.ANON_ATTRIBUTE, {"dlgtype": "accept"},)
+        not_existent = (By.ANON_ATTRIBUTE, {"anonid": "notexistent"},)
+
+        # By using the window document element
+        start_node = self.marionette.find_element(By.CSS_SELECTOR, ":root")
+        button = start_node.find_element(*accept_button)
+        self.assertEquals(HTMLElement, type(button))
+        with self.assertRaises(NoSuchElementException):
+            start_node.find_element(*not_existent)
+
+        # By using the default start node
+        self.assertEquals(button, self.marionette.find_element(*accept_button))
+        with self.assertRaises(NoSuchElementException):
+            self.marionette.find_element(*not_existent)
 
-        with self.assertRaises(NoSuchElementException):
-            el.find_element(By.ANON_ATTRIBUTE, {"anonid": "nonexistent"})
-        self.assertEquals([], el.find_elements(By.ANON_ATTRIBUTE, {"anonid": "nonexistent"}))
+    def test_find_anonymous_elements_by_attribute(self):
+        dialog_buttons = (By.ANON_ATTRIBUTE, {"anonid": "buttons"},)
+        not_existent = (By.ANON_ATTRIBUTE, {"anonid": "notexistent"},)
+
+        # By using the window document element
+        start_node = self.marionette.find_element(By.CSS_SELECTOR, ":root")
+        buttons = start_node.find_elements(*dialog_buttons)
+        self.assertEquals(1, len(buttons))
+        self.assertEquals(HTMLElement, type(buttons[0]))
+        self.assertListEqual([], start_node.find_elements(*not_existent))
+
+        # By using the default start node
+        self.assertListEqual(buttons, self.marionette.find_elements(*dialog_buttons))
+        self.assertListEqual([], self.marionette.find_elements(*not_existent))
 
     def test_find_anonymous_children(self):
-        el = Wait(self.marionette).until(element_present(By.ID, "dia"))
-        self.assertEquals(HTMLElement, type(el.find_element(By.ANON, None)))
-        self.assertEquals(2, len(el.find_elements(By.ANON, None)))
+        self.assertEquals(HTMLElement, type(self.marionette.find_element(By.ANON, None)))
+        self.assertEquals(2, len(self.marionette.find_elements(By.ANON, None)))
 
-        el = self.marionette.find_element(By.ID, "framebox")
+        frame = self.marionette.find_element(By.ID, "framebox")
         with self.assertRaises(NoSuchElementException):
-            el.find_element(By.ANON, None)
-        self.assertEquals([], el.find_elements(By.ANON, None))
+            frame.find_element(By.ANON, None)
+        self.assertListEqual([], frame.find_elements(By.ANON, None))