diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 5e50aa26235..0b3a0882ef9 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -1281,14 +1281,15 @@ class Marionette(object): NoSuchElementException will be raised. :param method: The method to use to locate the element; one of: "id", - "name", "class name", "tag name", "css selector", "link text", - "partial link text" and "xpath". Note that the methods supported in - the chrome dom are only "id", "class name", "tag name" and "xpath". + "name", "class name", "tag name", "css selector", "link text", + "partial link text", "xpath", "anon" and "anon attribute". + Note that the "name", "css selector", "link text" and + "partial link test" methods are not supported in the chrome dom. :param target: The target of the search. For example, if method = - "tag", target might equal "div". If method = "id", target would be - an element id. + "tag", target might equal "div". If method = "id", target would be + an element id. :param id: If specified, search for elements only inside the element - with the specified id. + with the specified id. ''' kwargs = { 'value': target, 'using': method } if id: @@ -1307,14 +1308,15 @@ class Marionette(object): time set by set_search_timeout(). :param method: The method to use to locate the elements; one of: - "id", "name", "class name", "tag name", "css selector", "link text", - "partial link text" and "xpath". Note that the methods supported in - the chrome dom are only "id", "class name", "tag name" and "xpath". + "id", "name", "class name", "tag name", "css selector", "link text", + "partial link text", "xpath", "anon" and "anon attribute". + Note that the "name", "css selector", "link text" and + "partial link test" methods are not supported in the chrome dom. :param target: The target of the search. For example, if method = - "tag", target might equal "div". If method = "id", target would be - an element id. + "tag", target might equal "div". If method = "id", target would be + an element id. :param id: If specified, search for elements only inside the element - with the specified id. + with the specified id. ''' kwargs = { 'value': target, 'using': method } if id: diff --git a/testing/marionette/client/marionette/tests/unit/test_switch_anonymous_content.py b/testing/marionette/client/marionette/tests/unit/test_anonymous_content.py similarity index 53% rename from testing/marionette/client/marionette/tests/unit/test_switch_anonymous_content.py rename to testing/marionette/client/marionette/tests/unit/test_anonymous_content.py index 53939281dd4..3949e29d349 100644 --- a/testing/marionette/client/marionette/tests/unit/test_switch_anonymous_content.py +++ b/testing/marionette/client/marionette/tests/unit/test_anonymous_content.py @@ -2,10 +2,13 @@ # 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 marionette import HTMLElement from marionette_test import MarionetteTestCase -from errors import JavascriptException, NoSuchElementException +from errors import NoSuchElementException +from expected import element_present +from wait import Wait -class TestSwitchFrameChrome(MarionetteTestCase): +class TestAnonymousContent(MarionetteTestCase): def setUp(self): MarionetteTestCase.setUp(self) self.marionette.set_context("chrome") @@ -20,7 +23,7 @@ class TestSwitchFrameChrome(MarionetteTestCase): self.marionette.switch_to_window(self.win) MarionetteTestCase.tearDown(self) - def test_switch(self): + def test_switch_to_anonymous_frame(self): self.marionette.find_element("id", "testAnonymousContentBox") anon_browser_el = self.marionette.find_element("id", "browser") self.assertTrue("test_anonymous_content.xul" in self.marionette.get_url()) @@ -28,3 +31,22 @@ class TestSwitchFrameChrome(MarionetteTestCase): self.assertTrue("test.xul" in self.marionette.get_url()) self.marionette.find_element("id", "testXulBox") self.assertRaises(NoSuchElementException, self.marionette.find_element, "id", "testAnonymousContentBox") + + def test_find_anonymous_element_by_attribute(self): + el = Wait(self.marionette).until(element_present("id", "dia")) + self.assertEquals(HTMLElement, type(el.find_element("anon attribute", {"anonid": "buttons"}))) + self.assertEquals(1, len(el.find_elements("anon attribute", {"anonid": "buttons"}))) + + with self.assertRaises(NoSuchElementException): + el.find_element("anon attribute", {"anonid": "nonexistent"}) + self.assertEquals([], el.find_elements("anon attribute", {"anonid": "nonexistent"})) + + def test_find_anonymous_children(self): + el = Wait(self.marionette).until(element_present("id", "dia")) + self.assertEquals(HTMLElement, type(el.find_element("anon", None))) + self.assertEquals(2, len(el.find_elements("anon", None))) + + el = self.marionette.find_element("id", "framebox") + with self.assertRaises(NoSuchElementException): + el.find_element("anon", None) + self.assertEquals([], el.find_elements("anon", None)) diff --git a/testing/marionette/client/marionette/tests/unit/unit-tests.ini b/testing/marionette/client/marionette/tests/unit/unit-tests.ini index e6fc4ed45a2..79e6cea8432 100644 --- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -87,7 +87,7 @@ browser = false [test_simpletest_chrome.js] [test_simpletest_timeout.js] [test_specialpowers.py] -[test_switch_anonymous_content.py] +[test_anonymous_content.py] [test_switch_frame.py] b2g = false skip-if = os == "win" # Bug 1078237 diff --git a/testing/marionette/marionette-elements.js b/testing/marionette/marionette-elements.js index 0d7ed9fa0c2..d13f9741229 100644 --- a/testing/marionette/marionette-elements.js +++ b/testing/marionette/marionette-elements.js @@ -20,7 +20,9 @@ this.EXPORTED_SYMBOLS = [ "LINK_TEXT", "PARTIAL_LINK_TEXT", "TAG", - "XPATH" + "XPATH", + "ANON", + "ANON_ATTRIBUTE" ]; const DOCUMENT_POSITION_DISCONNECTED = 1; @@ -36,6 +38,8 @@ this.LINK_TEXT = "link text"; this.PARTIAL_LINK_TEXT = "partial link text"; this.TAG = "tag name"; this.XPATH = "xpath"; +this.ANON= "anon"; +this.ANON_ATTRIBUTE = "anon attribute"; function ElementException(msg, num, stack) { this.message = msg; @@ -46,7 +50,7 @@ function ElementException(msg, num, stack) { this.ElementManager = function ElementManager(notSupported) { this.seenItems = {}; this.timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); - this.elementStrategies = [CLASS_NAME, SELECTOR, ID, NAME, LINK_TEXT, PARTIAL_LINK_TEXT, TAG, XPATH]; + this.elementStrategies = [CLASS_NAME, SELECTOR, ID, NAME, LINK_TEXT, PARTIAL_LINK_TEXT, TAG, XPATH, ANON, ANON_ATTRIBUTE]; for (let i = 0; i < notSupported.length; i++) { this.elementStrategies.splice(this.elementStrategies.indexOf(notSupported[i]), 1); } @@ -309,7 +313,14 @@ ElementManager.prototype = { return; } else { if (!searchTimeout || new Date().getTime() - startTime > searchTimeout) { - on_error("Unable to locate element: " + values.value, 7, null, command_id); + // Format message depending on strategy if necessary + let message = "Unable to locate element: " + values.value; + if (values.using == ANON) { + message = "Unable to locate anonymous children"; + } else if (values.using == ANON_ATTRIBUTE) { + message = "Unable to locate anonymous element: " + JSON.stringify(values.value); + } + on_error(message, 7, null, command_id); } else { values.time = startTime; this.timer.initWithCallback(this.find.bind(this, win, values, @@ -419,6 +430,16 @@ ElementManager.prototype = { case SELECTOR: element = startNode.querySelector(value); break; + case ANON: + element = rootNode.getAnonymousNodes(startNode); + if (element != null) { + element = element[0]; + } + break; + case ANON_ATTRIBUTE: + let attr = Object.keys(value)[0]; + element = rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]); + break; default: throw new ElementException("No such strategy", 500, null); } @@ -476,6 +497,16 @@ ElementManager.prototype = { case SELECTOR: elements = Array.slice(startNode.querySelectorAll(value)); break; + case ANON: + elements = rootNode.getAnonymousNodes(startNode) || []; + break; + case ANON_ATTRIBUTE: + let attr = Object.keys(value)[0]; + let el = rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]); + if (el != null) { + elements = [el]; + } + break; default: throw new ElementException("No such strategy", 500, null); }