Reputation: 85
I'm using python webdriver and I'm trying to make the system wait until the border colour of a password field has changed after a submit button has been clicked. The colour fades from one to the other and I can get the desired result using this: -
password_border_colour_after_click = ""
count = 0
while password_border_colour_after_click != "rgba(169, 68, 66, 1)":
password_border_colour_after_click = self.driver.find_element_by_name("password").value_of_css_property('border-bottom-color')
time.sleep(0.1)
count += 1
if password_border_colour_after_click == "rgba(169, 68, 66, 1)":
break
elif count > 50:
break
assert password_border_colour_after_click == "rgba(169, 68, 66, 1)"
It feels a bit clunky and is probably awful code so I was thinking there must be a way to package it all up in a wait command, but I can't get the syntax right.
Is it possible?
Upvotes: 0
Views: 2028
Reputation: 3513
Selenium API has a "wait for ..." functionality :
http://selenium-python.readthedocs.io/waits.html
Implement a expected_condition
and then combine it with wait
element = WebDriverWait(driver, 10)
.until(custom_expected_condition((By.ID, 'search-input'), argA, argB))
Good to know is that "wait" runs synchronously (blocks the thread) and can be combined with one of the following, out of the box:
- title_is
- title_contains
- presence_of_element_located
- visibility_of_element_located
- visibility_of
- presence_of_all_elements_located
- text_to_be_present_in_element
- text_to_be_present_in_element_value
- frame_to_be_available_and_switch_to_it
- invisibility_of_element_located
- element_to_be_clickable
- staleness_of
- element_to_be_selected
- element_located_to_be_selected
- element_selection_state_to_be
- element_located_selection_state_to_be
- alert_is_present
As you can see there is no element_has_style_value
condition, however one can always extend the "wait" with its own implementation.
Out of the docs a custom expected condition looks like so:
class element_has_css_class(object): """An expectation for checking that an element has a particular css class. locator - used to find the element returns the WebElement once it has the particular css class """ def __init__(self, locator, css_class): self.locator = locator self.css_class = css_class def __call__(self, driver): element = driver.find_element(*self.locator) # Finding the referenced element if self.css_class in element.get_attribute("class"): return element else: return False
And its usage is:
# Wait until an element with id='myNewInput' has class 'myCSSClass' wait = WebDriverWait(driver, 10) element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))
Putting everything together for an asset page like so : https://output.jsbin.com/xutipu
One can implement this:
class element_has_css_value(object):
"""An expectation for checking that an element has a particular css property and value.
locator - used to find the element
returns the WebElement once it has the particular css property and value
"""
def __init__(self, locator, css_property, css_value):
self.locator = locator
self.css_property = css_property
self.css_value = css_value
def matchPropertyAndValue(self, css_property, css_value):
return css_property == self.css_property and css_value == self.css_value;
def extractPropertyAndValue(self, cssStatement):
keyValue = cssStatement.split(':')
if len(keyValue) == 2:
key = keyValue[0].strip();
value = keyValue[1].strip();
return (key, value)
return (None, None)
def findProperty(self, entries):
foundProperty = False
for entry in entries:
(css_property, css_value) = self.extractPropertyAndValue(entry)
if css_value is None:
continue
foundProperty = self.matchPropertyAndValue(css_property, css_value);
if foundProperty :
break;
return foundProperty
def __call__(self, driver):
element = driver.find_element(*self.locator) # Finding the referenced element
styles = element.get_attribute("style")
entries = styles.split(';')
foundProperty = self.findProperty(entries);
if foundProperty :
return element
else:
return False
and use it like this :
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://output.jsbin.com/xutipu")
button = None;
try:
button = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "search-button"))
)
except e:
print(e);
driver.quit()
button.send_keys(Keys.RETURN)
try :
wait = WebDriverWait(driver, 10)
element = wait.until(element_has_css_value((By.ID, 'search-input'), "border-color", "rgb(169, 68, 66)"))
assert element;
print('Success');
finally:
driver.quit()
Upvotes: 3
Reputation: 1463
I don't know how to do this in Python since I'm not that familiar with the language, but in C# you can create delegate functions that act like custom ExpectedConditions
which you can use with the WebDriverWait
class.
The WebDriverWait
class waits n amount of seconds before throwing an exception.
Example (psuedo) code in C#:
public static class CustomExpectedConditions
{
public static Func<IWebDriver, bool> ElementAttributeContains(By locator, string attributeName, string expectedValue)
{
return (driver) => driver.FindElement(locator).GetAttribute(attributeName).Contains(expectedValue);
}
}
This allows you to use it like:
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
wait.Until(CustomExpectedConditions.ElementAttributeContains(By.Name("password"), "style", "rgba(169, 68, 66, 1)"));
I found this sample code for custom expected conditions in Python:
class element_has_css_class(object):
"""An expectation for checking that an element has a particular css class.
locator - used to find the element
returns the WebElement once it has the particular css class
"""
def __init__(self, locator, css_class):
self.locator = locator
self.css_class = css_class
def __call__(self, driver):
element = driver.find_element(*self.locator) # Finding the referenced element
if self.css_class in element.get_attribute("class"):
return element
else:
return False
# Wait until an element with id='myNewInput' has class 'myCSSClass'
wait = WebDriverWait(driver, 10)
element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))
Hope this will get you started in the right direction
Upvotes: 1