Skip to content

Commit

Permalink
[py] Expand element to be clickable in expected conditions(#9374)
Browse files Browse the repository at this point in the history

Co-authored-by: David Burns <[email protected]>
  • Loading branch information
maxtheaxe and AutomatedTester authored Apr 20, 2021
1 parent e5f0328 commit ca2c72a
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 6 deletions.
52 changes: 46 additions & 6 deletions py/selenium/webdriver/support/expected_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def title_is(title):
"""An expectation for checking the title of a page.
title is the expected title, which must be an exact match
returns True if the title matches, false otherwise."""

def _predicate(driver):
return driver.title == title

Expand All @@ -45,6 +46,7 @@ def title_contains(title):
substring. title is the fragment of title expected
returns True when the title matches, False otherwise
"""

def _predicate(driver):
return title in driver.title

Expand All @@ -57,6 +59,7 @@ def presence_of_element_located(locator):
locator - used to find the element
returns the WebElement once it is located
"""

def _predicate(driver):
return driver.find_element(*locator)

Expand All @@ -69,6 +72,7 @@ def url_contains(url):
url is the fragment of url expected,
returns True when the url matches, False otherwise
"""

def _predicate(driver):
return url in driver.current_url

Expand All @@ -79,6 +83,7 @@ def url_matches(pattern):
"""An expectation for checking the current url.
pattern is the expected pattern, which must be an exact match
returns True if the url matches, false otherwise."""

def _predicate(driver):
return bool(re.search(pattern, driver.current_url))

Expand All @@ -89,6 +94,7 @@ def url_to_be(url):
"""An expectation for checking the current url.
url is the expected url, which must be an exact match
returns True if the url matches, false otherwise."""

def _predicate(driver):
return url == driver.current_url

Expand All @@ -99,6 +105,7 @@ def url_changes(url):
"""An expectation for checking the current url.
url is the expected url, which must not be an exact match
returns True if the url is different, false otherwise."""

def _predicate(driver):
return url != driver.current_url

Expand All @@ -112,6 +119,7 @@ def visibility_of_element_located(locator):
locator - used to find the element
returns the WebElement once it is located and visible
"""

def _predicate(driver):
try:
return _element_if_visible(driver.find_element(*locator))
Expand All @@ -128,6 +136,7 @@ def visibility_of(element):
element is the WebElement
returns the (same) WebElement once it is visible
"""

def _predicate(_):
return _element_if_visible(element)

Expand All @@ -144,6 +153,7 @@ def presence_of_all_elements_located(locator):
locator is used to find the element
returns the list of WebElements once they are located
"""

def _predicate(driver):
return driver.find_elements(*locator)

Expand All @@ -156,6 +166,7 @@ def visibility_of_any_elements_located(locator):
locator is used to find the element
returns the list of WebElements once they are located
"""

def _predicate(driver):
return [element for element in driver.find_elements(*locator) if _element_if_visible(element)]

Expand All @@ -169,6 +180,7 @@ def visibility_of_all_elements_located(locator):
locator - used to find the elements
returns the list of WebElements once they are located and visible
"""

def _predicate(driver):
try:
elements = driver.find_elements(*locator)
Expand All @@ -187,6 +199,7 @@ def text_to_be_present_in_element(locator, text_):
specified element.
locator, text
"""

def _predicate(driver):
try:
element_text = driver.find_element(*locator).text
Expand All @@ -202,6 +215,7 @@ def text_to_be_present_in_element_value(locator, text_):
An expectation for checking if the given text is present in the element's
locator, text
"""

def _predicate(driver):
try:
element_text = driver.find_element(*locator).get_attribute("value")
Expand All @@ -217,6 +231,7 @@ def frame_to_be_available_and_switch_to_it(locator):
switch to. If the frame is available it switches the given driver to the
specified frame.
"""

def _predicate(driver):
try:
if hasattr(locator, '__iter__'):
Expand All @@ -236,6 +251,7 @@ def invisibility_of_element_located(locator):
locator used to find the element
"""

def _predicate(driver):
try:
target = locator
Expand All @@ -262,13 +278,23 @@ def invisibility_of_element(element):
return invisibility_of_element_located(element)


def element_to_be_clickable(locator):
""" An Expectation for checking an element is visible and enabled such that
you can click it."""
def element_to_be_clickable(mark):
"""
An Expectation for checking an element is visible and enabled such that
you can click it.
element is either a locator (text) or an WebElement
"""

# renamed argument to 'mark', to indicate that both locator
# and WebElement args are valid
def _predicate(driver):
element = visibility_of_element_located(locator)(driver)
if element and element.is_enabled():
return element
target = mark
if not isinstance(target, WebElement): # if given locator instead of WebElement
target = driver.find_element(*target) # grab element at locator
target = visibility_of(target)(driver)
if target and target.is_enabled():
return target
else:
return False

Expand All @@ -280,6 +306,7 @@ def staleness_of(element):
element is the element to wait for.
returns False if the element is still attached to the DOM, true otherwise.
"""

def _predicate(_):
try:
# Calling any method forces a staleness check
Expand All @@ -295,6 +322,7 @@ def element_to_be_selected(element):
""" An expectation for checking the selection is selected.
element is WebElement object
"""

def _predicate(_):
return element.is_selected()

Expand All @@ -304,6 +332,7 @@ def _predicate(_):
def element_located_to_be_selected(locator):
"""An expectation for the element to be located is selected.
locator is a tuple of (by, path)"""

def _predicate(driver):
return driver.find_element(*locator).is_selected()

Expand All @@ -315,6 +344,7 @@ def element_selection_state_to_be(element, is_selected):
element is WebElement object
is_selected is a Boolean."
"""

def _predicate(_):
return element.is_selected() == is_selected

Expand All @@ -327,6 +357,7 @@ def element_located_selection_state_to_be(locator, is_selected):
locator is a tuple of (by, path)
is_selected is a boolean
"""

def _predicate(driver):
try:
element = driver.find_element(*locator)
Expand All @@ -339,6 +370,7 @@ def _predicate(driver):

def number_of_windows_to_be(num_windows):
""" An expectation for the number of windows to be a certain value."""

def _predicate(driver):
return len(driver.window_handles) == num_windows

Expand All @@ -348,6 +380,7 @@ def _predicate(driver):
def new_window_is_opened(current_handles):
""" An expectation that a new window will be opened and have the number of
windows handles increase"""

def _predicate(driver):
return len(driver.window_handles) > len(current_handles)

Expand All @@ -369,6 +402,7 @@ def element_attribute_to_include(locator, attribute_):
specified element.
locator, attribute
"""

def _predicate(driver):
try:
element_attribute = driver.find_element(*locator).get_attribute(attribute_)
Expand All @@ -383,6 +417,7 @@ def any_of(*expected_conditions):
""" An expectation that any of multiple expected conditions is true.
Equivalent to a logical 'OR'.
Returns results of the first matching condition, or False if none do. """

def any_of_condition(driver):
for expected_condition in expected_conditions:
try:
Expand All @@ -392,6 +427,7 @@ def any_of_condition(driver):
except WebDriverException:
pass
return False

return any_of_condition


Expand All @@ -400,6 +436,7 @@ def all_of(*expected_conditions):
Equivalent to a logical 'AND'.
Returns: When any ExpectedCondition is not met: False.
When all ExpectedConditions are met: A List with each ExpectedCondition's return value. """

def all_of_condition(driver):
results = []
for expected_condition in expected_conditions:
Expand All @@ -411,13 +448,15 @@ def all_of_condition(driver):
except WebDriverException:
return False
return results

return all_of_condition


def none_of(*expected_conditions):
""" An expectation that none of 1 or multiple expected conditions is true.
Equivalent to a logical 'NOT-OR'.
Returns a Boolean """

def none_of_condition(driver):
for expected_condition in expected_conditions:
try:
Expand All @@ -427,4 +466,5 @@ def none_of_condition(driver):
except WebDriverException:
pass
return True

return none_of_condition
29 changes: 29 additions & 0 deletions py/test/selenium/webdriver/support/expected_conditions_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,32 @@ def test_none_of_false(driver, pages):
with pytest.raises(TimeoutException):
WebDriverWait(driver, 0.1).until(EC.none_of(
EC.title_is("Nope"), EC.title_is("Hello WebDriver")))


def test_clickable_locator_true(driver, pages):
pages.load("simpleTest.html")
WebDriverWait(driver, 0.1).until(
EC.element_to_be_clickable((By.ID, "multilinelink")))


def test_clickable_locator_false(driver, pages):
pages.load("simpleTest.html")
with pytest.raises(TimeoutException):
# text element, should not be clickable
WebDriverWait(driver, 0.1).until(
EC.element_to_be_clickable((By.ID, "hiddenline")))


def test_clickable_element_true(driver, pages):
pages.load("simpleTest.html")
target = (By.ID, "multilinelink")
element = driver.find_element(*target) # grab element at locator
WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element))


def test_clickable_element_false(driver, pages):
pages.load("simpleTest.html")
with pytest.raises(TimeoutException):
target = (By.ID, "hiddenline") # text, should not be clickable
element = driver.find_element(*target) # grab element at locator
WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element))

0 comments on commit ca2c72a

Please sign in to comment.