Skip to content

Commit ca2c72a

Browse files
[py] Expand element to be clickable in expected conditions(#9374)
Co-authored-by: David Burns <david.burns@theautomatedtester.co.uk>
1 parent e5f0328 commit ca2c72a

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

py/selenium/webdriver/support/expected_conditions.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def title_is(title):
3434
"""An expectation for checking the title of a page.
3535
title is the expected title, which must be an exact match
3636
returns True if the title matches, false otherwise."""
37+
3738
def _predicate(driver):
3839
return driver.title == title
3940

@@ -45,6 +46,7 @@ def title_contains(title):
4546
substring. title is the fragment of title expected
4647
returns True when the title matches, False otherwise
4748
"""
49+
4850
def _predicate(driver):
4951
return title in driver.title
5052

@@ -57,6 +59,7 @@ def presence_of_element_located(locator):
5759
locator - used to find the element
5860
returns the WebElement once it is located
5961
"""
62+
6063
def _predicate(driver):
6164
return driver.find_element(*locator)
6265

@@ -69,6 +72,7 @@ def url_contains(url):
6972
url is the fragment of url expected,
7073
returns True when the url matches, False otherwise
7174
"""
75+
7276
def _predicate(driver):
7377
return url in driver.current_url
7478

@@ -79,6 +83,7 @@ def url_matches(pattern):
7983
"""An expectation for checking the current url.
8084
pattern is the expected pattern, which must be an exact match
8185
returns True if the url matches, false otherwise."""
86+
8287
def _predicate(driver):
8388
return bool(re.search(pattern, driver.current_url))
8489

@@ -89,6 +94,7 @@ def url_to_be(url):
8994
"""An expectation for checking the current url.
9095
url is the expected url, which must be an exact match
9196
returns True if the url matches, false otherwise."""
97+
9298
def _predicate(driver):
9399
return url == driver.current_url
94100

@@ -99,6 +105,7 @@ def url_changes(url):
99105
"""An expectation for checking the current url.
100106
url is the expected url, which must not be an exact match
101107
returns True if the url is different, false otherwise."""
108+
102109
def _predicate(driver):
103110
return url != driver.current_url
104111

@@ -112,6 +119,7 @@ def visibility_of_element_located(locator):
112119
locator - used to find the element
113120
returns the WebElement once it is located and visible
114121
"""
122+
115123
def _predicate(driver):
116124
try:
117125
return _element_if_visible(driver.find_element(*locator))
@@ -128,6 +136,7 @@ def visibility_of(element):
128136
element is the WebElement
129137
returns the (same) WebElement once it is visible
130138
"""
139+
131140
def _predicate(_):
132141
return _element_if_visible(element)
133142

@@ -144,6 +153,7 @@ def presence_of_all_elements_located(locator):
144153
locator is used to find the element
145154
returns the list of WebElements once they are located
146155
"""
156+
147157
def _predicate(driver):
148158
return driver.find_elements(*locator)
149159

@@ -156,6 +166,7 @@ def visibility_of_any_elements_located(locator):
156166
locator is used to find the element
157167
returns the list of WebElements once they are located
158168
"""
169+
159170
def _predicate(driver):
160171
return [element for element in driver.find_elements(*locator) if _element_if_visible(element)]
161172

@@ -169,6 +180,7 @@ def visibility_of_all_elements_located(locator):
169180
locator - used to find the elements
170181
returns the list of WebElements once they are located and visible
171182
"""
183+
172184
def _predicate(driver):
173185
try:
174186
elements = driver.find_elements(*locator)
@@ -187,6 +199,7 @@ def text_to_be_present_in_element(locator, text_):
187199
specified element.
188200
locator, text
189201
"""
202+
190203
def _predicate(driver):
191204
try:
192205
element_text = driver.find_element(*locator).text
@@ -202,6 +215,7 @@ def text_to_be_present_in_element_value(locator, text_):
202215
An expectation for checking if the given text is present in the element's
203216
locator, text
204217
"""
218+
205219
def _predicate(driver):
206220
try:
207221
element_text = driver.find_element(*locator).get_attribute("value")
@@ -217,6 +231,7 @@ def frame_to_be_available_and_switch_to_it(locator):
217231
switch to. If the frame is available it switches the given driver to the
218232
specified frame.
219233
"""
234+
220235
def _predicate(driver):
221236
try:
222237
if hasattr(locator, '__iter__'):
@@ -236,6 +251,7 @@ def invisibility_of_element_located(locator):
236251
237252
locator used to find the element
238253
"""
254+
239255
def _predicate(driver):
240256
try:
241257
target = locator
@@ -262,13 +278,23 @@ def invisibility_of_element(element):
262278
return invisibility_of_element_located(element)
263279

264280

265-
def element_to_be_clickable(locator):
266-
""" An Expectation for checking an element is visible and enabled such that
267-
you can click it."""
281+
def element_to_be_clickable(mark):
282+
"""
283+
An Expectation for checking an element is visible and enabled such that
284+
you can click it.
285+
286+
element is either a locator (text) or an WebElement
287+
"""
288+
289+
# renamed argument to 'mark', to indicate that both locator
290+
# and WebElement args are valid
268291
def _predicate(driver):
269-
element = visibility_of_element_located(locator)(driver)
270-
if element and element.is_enabled():
271-
return element
292+
target = mark
293+
if not isinstance(target, WebElement): # if given locator instead of WebElement
294+
target = driver.find_element(*target) # grab element at locator
295+
target = visibility_of(target)(driver)
296+
if target and target.is_enabled():
297+
return target
272298
else:
273299
return False
274300

@@ -280,6 +306,7 @@ def staleness_of(element):
280306
element is the element to wait for.
281307
returns False if the element is still attached to the DOM, true otherwise.
282308
"""
309+
283310
def _predicate(_):
284311
try:
285312
# Calling any method forces a staleness check
@@ -295,6 +322,7 @@ def element_to_be_selected(element):
295322
""" An expectation for checking the selection is selected.
296323
element is WebElement object
297324
"""
325+
298326
def _predicate(_):
299327
return element.is_selected()
300328

@@ -304,6 +332,7 @@ def _predicate(_):
304332
def element_located_to_be_selected(locator):
305333
"""An expectation for the element to be located is selected.
306334
locator is a tuple of (by, path)"""
335+
307336
def _predicate(driver):
308337
return driver.find_element(*locator).is_selected()
309338

@@ -315,6 +344,7 @@ def element_selection_state_to_be(element, is_selected):
315344
element is WebElement object
316345
is_selected is a Boolean."
317346
"""
347+
318348
def _predicate(_):
319349
return element.is_selected() == is_selected
320350

@@ -327,6 +357,7 @@ def element_located_selection_state_to_be(locator, is_selected):
327357
locator is a tuple of (by, path)
328358
is_selected is a boolean
329359
"""
360+
330361
def _predicate(driver):
331362
try:
332363
element = driver.find_element(*locator)
@@ -339,6 +370,7 @@ def _predicate(driver):
339370

340371
def number_of_windows_to_be(num_windows):
341372
""" An expectation for the number of windows to be a certain value."""
373+
342374
def _predicate(driver):
343375
return len(driver.window_handles) == num_windows
344376

@@ -348,6 +380,7 @@ def _predicate(driver):
348380
def new_window_is_opened(current_handles):
349381
""" An expectation that a new window will be opened and have the number of
350382
windows handles increase"""
383+
351384
def _predicate(driver):
352385
return len(driver.window_handles) > len(current_handles)
353386

@@ -369,6 +402,7 @@ def element_attribute_to_include(locator, attribute_):
369402
specified element.
370403
locator, attribute
371404
"""
405+
372406
def _predicate(driver):
373407
try:
374408
element_attribute = driver.find_element(*locator).get_attribute(attribute_)
@@ -383,6 +417,7 @@ def any_of(*expected_conditions):
383417
""" An expectation that any of multiple expected conditions is true.
384418
Equivalent to a logical 'OR'.
385419
Returns results of the first matching condition, or False if none do. """
420+
386421
def any_of_condition(driver):
387422
for expected_condition in expected_conditions:
388423
try:
@@ -392,6 +427,7 @@ def any_of_condition(driver):
392427
except WebDriverException:
393428
pass
394429
return False
430+
395431
return any_of_condition
396432

397433

@@ -400,6 +436,7 @@ def all_of(*expected_conditions):
400436
Equivalent to a logical 'AND'.
401437
Returns: When any ExpectedCondition is not met: False.
402438
When all ExpectedConditions are met: A List with each ExpectedCondition's return value. """
439+
403440
def all_of_condition(driver):
404441
results = []
405442
for expected_condition in expected_conditions:
@@ -411,13 +448,15 @@ def all_of_condition(driver):
411448
except WebDriverException:
412449
return False
413450
return results
451+
414452
return all_of_condition
415453

416454

417455
def none_of(*expected_conditions):
418456
""" An expectation that none of 1 or multiple expected conditions is true.
419457
Equivalent to a logical 'NOT-OR'.
420458
Returns a Boolean """
459+
421460
def none_of_condition(driver):
422461
for expected_condition in expected_conditions:
423462
try:
@@ -427,4 +466,5 @@ def none_of_condition(driver):
427466
except WebDriverException:
428467
pass
429468
return True
469+
430470
return none_of_condition

py/test/selenium/webdriver/support/expected_conditions_tests.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,32 @@ def test_none_of_false(driver, pages):
6464
with pytest.raises(TimeoutException):
6565
WebDriverWait(driver, 0.1).until(EC.none_of(
6666
EC.title_is("Nope"), EC.title_is("Hello WebDriver")))
67+
68+
69+
def test_clickable_locator_true(driver, pages):
70+
pages.load("simpleTest.html")
71+
WebDriverWait(driver, 0.1).until(
72+
EC.element_to_be_clickable((By.ID, "multilinelink")))
73+
74+
75+
def test_clickable_locator_false(driver, pages):
76+
pages.load("simpleTest.html")
77+
with pytest.raises(TimeoutException):
78+
# text element, should not be clickable
79+
WebDriverWait(driver, 0.1).until(
80+
EC.element_to_be_clickable((By.ID, "hiddenline")))
81+
82+
83+
def test_clickable_element_true(driver, pages):
84+
pages.load("simpleTest.html")
85+
target = (By.ID, "multilinelink")
86+
element = driver.find_element(*target) # grab element at locator
87+
WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element))
88+
89+
90+
def test_clickable_element_false(driver, pages):
91+
pages.load("simpleTest.html")
92+
with pytest.raises(TimeoutException):
93+
target = (By.ID, "hiddenline") # text, should not be clickable
94+
element = driver.find_element(*target) # grab element at locator
95+
WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element))

0 commit comments

Comments
 (0)