Bug 1272653 - Implement WebDriver command Get Element Property; r?jgriffin
MozReview-Commit-ID: 5lfZkSYPthb
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -55,25 +55,30 @@ class HTMLElement(object):
"""Returns a list of all ``HTMLElement`` instances that match the
specified method and target in the current context.
For more details on this function, see the find_elements method
in the Marionette class.
"""
return self.marionette.find_elements(method, target, self.id)
- def get_attribute(self, attribute):
+ def get_attribute(self, name):
"""Returns the requested attribute, or None if no attribute
is set.
-
- :param attribute: The name of the attribute.
"""
- body = {"id": self.id, "name": attribute}
+ body = {"id": self.id, "name": name}
return self.marionette._send_message("getElementAttribute", body, key="value")
+ def get_property(self, name):
+ """Returns the requested property, or None if the property is
+ not set.
+ """
+ body = {"id": self.id, "name": name}
+ return self.marionette._send_message("getElementProperty", body, key="value")
+
def click(self):
self.marionette._send_message("clickElement", {"id": self.id})
def tap(self, x=None, y=None):
"""Simulates a set of tap events on the element.
:param x: X coordinate of tap event. If not given, default to
the centre of the element.
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -1746,19 +1746,22 @@ GeckoDriver.prototype.clickElement = fun
break;
}
};
/**
* Get a given attribute of an element.
*
* @param {string} id
- * Reference ID to the element that will be inspected.
+ * Web element reference ID to the element that will be inspected.
* @param {string} name
- * Name of the attribute to retrieve.
+ * Name of the attribute which value to retrieve.
+ *
+ * @return {string}
+ * Value of the attribute.
*/
GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
let {id, name} = cmd.parameters;
switch (this.context) {
case Context.CHROME:
let win = this.getCurrentWindow();
let el = this.curBrowser.elementManager.getKnownElement(id, {frame: win});
@@ -1767,16 +1770,39 @@ GeckoDriver.prototype.getElementAttribut
case Context.CONTENT:
resp.body.value = yield this.listener.getElementAttribute(id, name);
break;
}
};
/**
+ * Returns the value of a property associated with given element.
+ *
+ * @param {string} id
+ * Web element reference ID to the element that will be inspected.
+ * @param {string} name
+ * Name of the property which value to retrieve.
+ *
+ * @return {string}
+ * Value of the property.
+ */
+GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
+ let {id, name} = cmd.parameters;
+
+ switch (this.context) {
+ case Context.CHROME:
+ throw new UnsupportedOperationError();
+
+ case Context.CONTENT:
+ return this.listener.getElementProperty(id, name);
+ }
+};
+
+/**
* Get the text of an element, if any. Includes the text of all child
* elements.
*
* @param {string} id
* Reference ID to the element that will be inspected.
*/
GeckoDriver.prototype.getElementText = function*(cmd, resp) {
let id = cmd.parameters.id;
@@ -2703,16 +2729,17 @@ GeckoDriver.prototype.commands = {
"multiAction": GeckoDriver.prototype.multiAction,
"executeAsyncScript": GeckoDriver.prototype.executeAsyncScript,
"executeJSScript": GeckoDriver.prototype.executeJSScript,
"setSearchTimeout": GeckoDriver.prototype.setSearchTimeout,
"findElement": GeckoDriver.prototype.findElement,
"findElements": GeckoDriver.prototype.findElements,
"clickElement": GeckoDriver.prototype.clickElement,
"getElementAttribute": GeckoDriver.prototype.getElementAttribute,
+ "getElementProperty": GeckoDriver.prototype.getElementProperty,
"getElementText": GeckoDriver.prototype.getElementText,
"getElementTagName": GeckoDriver.prototype.getElementTagName,
"isElementDisplayed": GeckoDriver.prototype.isElementDisplayed,
"getElementValueOfCssProperty": GeckoDriver.prototype.getElementValueOfCssProperty,
"getElementRect": GeckoDriver.prototype.getElementRect,
"isElementEnabled": GeckoDriver.prototype.isElementEnabled,
"isElementSelected": GeckoDriver.prototype.isElementSelected,
"sendKeysToElement": GeckoDriver.prototype.sendKeysToElement,
--- a/testing/marionette/harness/marionette/tests/unit/test_element_state.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_element_state.py
@@ -1,16 +1,28 @@
# 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/.
+import urllib
+
from marionette import MarionetteTestCase
from marionette_driver.by import By
+def inline(doc):
+ return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
+
+
+attribute = inline("<input foo=bar>")
+input = inline("<input>")
+disabled = inline("<input disabled=baz>")
+check = inline("<input type=checkbox>")
+
+
class TestIsElementEnabled(MarionetteTestCase):
def test_is_enabled(self):
test_html = self.marionette.absolute_url("test.html")
self.marionette.navigate(test_html)
l = self.marionette.find_element(By.NAME, "myCheckBox")
self.assertTrue(l.is_enabled())
self.marionette.execute_script("arguments[0].disabled = true;", [l])
self.assertFalse(l.is_enabled())
@@ -33,8 +45,40 @@ class TestGetElementAttribute(Marionette
l = self.marionette.find_element(By.ID, "mozLink")
self.assertEqual("mozLink", l.get_attribute("id"))
def test_boolean(self):
test_html = self.marionette.absolute_url("html5/boolean_attributes.html")
self.marionette.navigate(test_html)
disabled = self.marionette.find_element(By.ID, "disabled")
self.assertEqual('true', disabled.get_attribute("disabled"))
+
+
+class TestGetElementProperty(MarionetteTestCase):
+ def test_get(self):
+ self.marionette.navigate(disabled)
+ el = self.marionette.find_element(By.TAG_NAME, "input")
+ prop = el.get_property("disabled")
+ self.assertIsInstance(prop, bool)
+ self.assertTrue(prop)
+
+ def test_missing_property_returns_false(self):
+ self.marionette.navigate(input)
+ el = self.marionette.find_element(By.TAG_NAME, "input")
+ prop = el.get_property("checked")
+ self.assertIsInstance(prop, bool)
+ self.assertFalse(prop)
+
+ def test_attribute_not_returned(self):
+ self.marionette.navigate(attribute)
+ el = self.marionette.find_element(By.TAG_NAME, "input")
+ self.assertEqual(el.get_property("foo"), None)
+
+ def test_manipulated_element(self):
+ self.marionette.navigate(check)
+ el = self.marionette.find_element(By.TAG_NAME, "input")
+ self.assertEqual(el.get_property("checked"), False)
+
+ el.click()
+ self.assertEqual(el.get_property("checked"), True)
+
+ el.click()
+ self.assertEqual(el.get_property("checked"), False)
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -208,16 +208,17 @@ function removeMessageListenerId(message
}
var getTitleFn = dispatch(getTitle);
var getPageSourceFn = dispatch(getPageSource);
var getActiveElementFn = dispatch(getActiveElement);
var clickElementFn = dispatch(clickElement);
var goBackFn = dispatch(goBack);
var getElementAttributeFn = dispatch(getElementAttribute);
+var getElementPropertyFn = dispatch(getElementProperty);
var getElementTextFn = dispatch(getElementText);
var getElementTagNameFn = dispatch(getElementTagName);
var getElementRectFn = dispatch(getElementRect);
var isElementEnabledFn = dispatch(isElementEnabled);
var getCurrentUrlFn = dispatch(getCurrentUrl);
var findElementContentFn = dispatch(findElementContent);
var findElementsContentFn = dispatch(findElementsContent);
var isElementSelectedFn = dispatch(isElementSelected);
@@ -259,16 +260,17 @@ function startListeners() {
addMessageListenerId("Marionette:goBack", goBackFn);
addMessageListenerId("Marionette:goForward", goForward);
addMessageListenerId("Marionette:refresh", refresh);
addMessageListenerId("Marionette:findElementContent", findElementContentFn);
addMessageListenerId("Marionette:findElementsContent", findElementsContentFn);
addMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
addMessageListenerId("Marionette:clickElement", clickElementFn);
addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
+ addMessageListenerId("Marionette:getElementProperty", getElementPropertyFn);
addMessageListenerId("Marionette:getElementText", getElementTextFn);
addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
addMessageListenerId("Marionette:getElementRect", getElementRectFn);
addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
addMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
@@ -363,16 +365,17 @@ function deleteSession(msg) {
removeMessageListenerId("Marionette:goBack", goBackFn);
removeMessageListenerId("Marionette:goForward", goForward);
removeMessageListenerId("Marionette:refresh", refresh);
removeMessageListenerId("Marionette:findElementContent", findElementContentFn);
removeMessageListenerId("Marionette:findElementsContent", findElementsContentFn);
removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
removeMessageListenerId("Marionette:clickElement", clickElementFn);
removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
+ removeMessageListenerId("Marionette:getElementProperty", getElementPropertyFn);
removeMessageListenerId("Marionette:getElementText", getElementTextFn);
removeMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
removeMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
@@ -1051,32 +1054,26 @@ function getActiveElement() {
function clickElement(id) {
let el = elementManager.getKnownElement(id, curContainer);
return interaction.clickElement(
el,
!!capabilities.raisesAccessibilityExceptions,
capabilities.specificationLevel >= 1);
}
-/**
- * Get a given attribute of an element.
- *
- * @param {WebElement} id
- * Reference to the web element to get the attribute of.
- * @param {string} name
- * Name of the attribute.
- *
- * @return {string}
- * The value of the attribute.
- */
function getElementAttribute(id, name) {
let el = elementManager.getKnownElement(id, curContainer);
return atom.getElementAttribute(el, name, curContainer.frame);
}
+function getElementProperty(id, name) {
+ let el = elementManager.getKnownElement(id, curContainer);
+ return el[name];
+}
+
/**
* Get the text of this element. This includes text from child elements.
*
* @param {WebElement} id
* Reference to web element.
*
* @return {string}
* Text of element.