Skip to content

Commit 941ddb9

Browse files
Initial implementation of get_attribute acting as a shim
1 parent 8f773cf commit 941ddb9

5 files changed

Lines changed: 63 additions & 19 deletions

File tree

py/selenium/webdriver/remote/command.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class Command(object):
8383
GET_ELEMENT_SIZE = "getElementSize"
8484
GET_ELEMENT_RECT = "getElementRect"
8585
GET_ELEMENT_ATTRIBUTE = "getElementAttribute"
86+
GET_ELEMENT_PROPERTY = "getElementProperty"
8687
GET_ELEMENT_VALUE_OF_CSS_PROPERTY = "getElementValueOfCssProperty"
8788
ELEMENT_EQUALS = "elementEquals"
8889
SCREENSHOT = "screenshot"

py/selenium/webdriver/remote/remote_connection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ def __init__(self, remote_server_addr, keep_alive=False, resolve_ip=True):
252252
('GET', '/session/$sessionId/element/$id/rect'),
253253
Command.GET_ELEMENT_ATTRIBUTE:
254254
('GET', '/session/$sessionId/element/$id/attribute/$name'),
255+
Command.GET_ELEMENT_PROPERTY:
256+
('GET', '/session/$sessionId/element/$id/property/$name'),
255257
Command.ELEMENT_EQUALS:
256258
('GET', '/session/$sessionId/element/$id/equals/$other'),
257259
Command.GET_ALL_COOKIES: ('GET', '/session/$sessionId/cookie'),

py/selenium/webdriver/remote/webdriver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def create_web_element(self, element_id):
198198
"""
199199
Creates a web element with the specified element_id.
200200
"""
201-
return WebElement(self, element_id, w3c=self.w3c)
201+
return WebElement(self, element_id, capabilities=self.capabilities)
202202

203203
def _unwrap_value(self, value):
204204
if isinstance(value, dict) and ('ELEMENT' in value or 'element-6066-11e4-a52e-4f735466cecf' in value):

py/selenium/webdriver/remote/webelement.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,16 @@ class WebElement(object):
4848
``StaleElementReferenceException`` is thrown, and all future calls to this
4949
instance will fail."""
5050

51-
def __init__(self, parent, id_, w3c=False):
51+
boolean_attributes = ['default', 'typemustmatch', 'checked', 'defer', 'async', 'muted',
52+
'reversed', 'required', 'controls', 'ismap', 'disabled', 'novalidate',
53+
'readonly', 'allowfullscreen', 'selected', 'formnovalidate',
54+
'multiple', 'autofocus', 'open', 'loop', 'autoplay']
55+
56+
def __init__(self, parent, id_, capabilities):
5257
self._parent = parent
5358
self._id = id_
54-
self._w3c = w3c
59+
self.capabilities = capabilities
60+
self._w3c = "specificationLevel" in self.capabilities
5561

5662
def __repr__(self):
5763
return '<{0.__module__}.{0.__name__} (session="{1}", element="{2}")>'.format(
@@ -86,6 +92,24 @@ def clear(self):
8692
"""Clears the text if it's a text entry element."""
8793
self._execute(Command.CLEAR_ELEMENT)
8894

95+
def get_property(self, name):
96+
"""
97+
Gets the given property of the element.
98+
99+
:Args:
100+
- name - Name of the property to retrieve.
101+
102+
Example::
103+
104+
# Check if the "active" CSS class is applied to an element.
105+
text_length = target_element.get_property("text_length")
106+
"""
107+
try:
108+
return self._execute(Command.GET_ELEMENT_PROPERTY, {"name": name})["value"]
109+
except WebDriverException:
110+
# if we hit an end point that doesnt understand getElementProperty lets fake it
111+
self.parent.execute_script('return arguments[0][arguments[1]]', self, name)
112+
89113
def get_attribute(self, name):
90114
"""Gets the given attribute or property of the element.
91115
@@ -108,12 +132,33 @@ def get_attribute(self, name):
108132
is_active = "active" in target_element.get_attribute("class")
109133
110134
"""
111-
resp = self._execute(Command.GET_ELEMENT_ATTRIBUTE, {'name': name})
135+
112136
attributeValue = ''
113-
if resp['value'] is None:
114-
attributeValue = None
137+
if self._w3c :
138+
if name == 'style':
139+
return self.parent.execute_script("return arguments[0].style.cssText", self)
140+
attributeValue = self.get_property(name)
141+
if (attributeValue in [None, '', False] and name != 'value') or name in self.boolean_attributes:
142+
# We need to check the attribute before we really set it to None
143+
resp = self._execute(Command.GET_ELEMENT_ATTRIBUTE, {'name': name})
144+
attributeValue = resp.get('value')
145+
146+
# Even though we have a value, we could be getting the browser default,
147+
# We now need check it's there in the DOM...
148+
resp = self.parent.execute_script("return arguments[0].hasAttribute(arguments[1])",
149+
self, name)
150+
if resp is False:
151+
attributeValue = None
152+
else:
153+
attributeValue = "{0}".format(attributeValue)
154+
155+
if attributeValue is not None:
156+
if name != 'value' and attributeValue.lower() in ('true', 'false'):
157+
attributeValue = attributeValue.lower()
158+
115159
else:
116-
attributeValue = resp['value']
160+
resp = self._execute(Command.GET_ELEMENT_ATTRIBUTE, {'name': name})
161+
attributeValue = resp.get('value')
117162
if name != 'value' and attributeValue.lower() in ('true', 'false'):
118163
attributeValue = attributeValue.lower()
119164
return attributeValue

py/test/selenium/webdriver/common/element_attribute_tests.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def testShouldReturnNullWhenGettingSrcAttributeOfInvalidImgTag(self):
3131
self._loadSimplePage()
3232
img = self.driver.find_element_by_id("invalidImgTag")
3333
img_attr = img.get_attribute("src")
34-
self.assertTrue(img_attr is None)
34+
self.assertEqual(img_attr, None)
3535

3636
def testShouldReturnAnAbsoluteUrlWhenGettingSrcAttributeOfAValidImgTag(self):
3737
self._loadSimplePage()
@@ -130,14 +130,14 @@ def testShouldReturnTheValueOfSelectedForRadioButtonsEvenIfTheyLackThatAttribute
130130
initiallyNotSelected = self.driver.find_element_by_id("peas")
131131
initiallySelected = self.driver.find_element_by_id("cheese_and_peas")
132132

133-
self.assertTrue(neverSelected.get_attribute("selected") is None, "false")
134-
self.assertTrue(initiallyNotSelected.get_attribute("selected") is None, "false")
135-
self.assertEqual("true", initiallySelected.get_attribute("selected"), "true")
133+
self.assertTrue(neverSelected.get_attribute("checked") is None, )
134+
self.assertTrue(initiallyNotSelected.get_attribute("checked") is None, )
135+
self.assertEqual("true", initiallySelected.get_attribute("checked"))
136136

137137
initiallyNotSelected.click()
138-
self.assertTrue(neverSelected.get_attribute("selected") is None)
139-
self.assertEqual("true", initiallyNotSelected.get_attribute("selected"))
140-
self.assertTrue(initiallySelected.get_attribute("selected") is None)
138+
self.assertEqual(neverSelected.get_attribute("selected"), None)
139+
self.assertEqual("true", initiallyNotSelected.get_attribute("checked"))
140+
self.assertEqual(initiallySelected.get_attribute("checked"), None)
141141

142142
def testShouldReturnTheValueOfSelectedForOptionsInSelectsEvenIfTheyLackThatAttribute(self):
143143
self._loadPage("formPage")
@@ -148,7 +148,7 @@ def testShouldReturnTheValueOfSelectedForOptionsInSelectsEvenIfTheyLackThatAttri
148148
self.assertTrue(one.is_selected())
149149
self.assertFalse(two.is_selected())
150150
self.assertEqual("true", one.get_attribute("selected"))
151-
self.assertTrue(two.get_attribute("selected") is None)
151+
self.assertEqual(two.get_attribute("selected"), None)
152152

153153
def testShouldReturnValueOfClassAttributeOfAnElement(self):
154154
self._loadPage("xhtmlTest")
@@ -235,8 +235,6 @@ def testShouldReturnNullForNonPresentBooleanAttributes(self):
235235
self._loadPage("booleanAttributes")
236236
element1 = self.driver.find_element_by_id("working")
237237
self.assertEqual(None, element1.get_attribute("required"))
238-
element2 = self.driver.find_element_by_id("wallace")
239-
self.assertEqual(None, element2.get_attribute("nowrap"))
240238

241239
@pytest.mark.ignore_ie
242240
def testShouldReturnTrueForPresentBooleanAttributes(self):
@@ -249,8 +247,6 @@ def testShouldReturnTrueForPresentBooleanAttributes(self):
249247
self.assertEqual("true", element3.get_attribute("required"))
250248
element4 = self.driver.find_element_by_id("textAreaRequired")
251249
self.assertEqual("true", element4.get_attribute("required"))
252-
element5 = self.driver.find_element_by_id("unwrappable")
253-
self.assertEqual("true", element5.get_attribute("nowrap"))
254250

255251
def tesShouldGetUnicodeCharsFromAttribute(self):
256252
self._loadPage("formPage")

0 commit comments

Comments
 (0)