Reputation: 14640
A lot of times I want the webdriver to wait for presence of one of the two elements. Normally this happens when I am expecting the page to be showing either element1 in some cases or element 2. Currently I am doing this sequentially using two waits, but it's inefficient since I need to wait 2 times. Is there any way to combine the two waits into one? In other words I want to wait until element1 or element2 is present.
try:
element = WebDriverWait(self.browser, 15).until(EC.presence_of_element_located((By.ID, "elem1")))
element.click()
return "elem1"
except:
print "failed to find elem1"
try:
element = WebDriverWait(self.browser, 5).until(EC.presence_of_element_located((By.ID, "elem2")))
return "elem2"
except:
print "sth wrong!"
raise Exception("Sth Wrong!")
return "Should not get here"
Upvotes: 28
Views: 17979
Reputation: 3804
From a suggested edit:
You can do an OR
driverWait.until(ExpectedConditions.any_of(
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.something")),
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.anything"))));
or and AND
driverWait.until(ExpectedConditions.all_of(
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.something")),
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.anything"))));
Upvotes: 0
Reputation: 1364
For those looking to await the appearance of any one of several elements without the inefficiency of waiting for each in sequence this method works. It waits for any of the elements defined by their IDs and promptly returns the first that appears. (you can use other selectors like XPath as well)
def get_any_elem(driver, timeout, *element_ids):
def condition(d):
for elem_id in element_ids:
try:
element = d.find_element(By.ID, elem_id)
if element:
return element
except NoSuchElementException:
continue
return False
return WebDriverWait(driver, timeout).until(condition)
Upvotes: 0
Reputation: 5476
You can use the any_of
method which is implemented inside the ExpectedConditions
section to check if any of the elements are available and this is relevant to the logical expression - "OR".
Example:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(driver, 40).until(EC.any_of(
EC.visibility_of_element_located((By.ID, 'elem1')),
EC.visibility_of_element_located((By.ID, 'elem2'))
)
)
Upvotes: 4
Reputation: 1068
This is an alternative solution while I was having problems with other solutions.
For example, if we only have 2 conditions, and 1st is never satisfied while the 2nd is already satisfied. Then the other solutions block until the end of wait_delay
before return the result; while the following solution skip it:
WebDriverWait(driver, wait_delay).until(
wait_for_any([
EC.presence_of_element_located(locator)
for locator in locators
]))
where
class wait_for_any:
def __init__(self, methods):
self.methods = methods
def __call__(self, driver):
for method in self.methods:
try:
if method(driver):
return True
except Exception:
pass
return False
Upvotes: 0
Reputation: 380
You can do an OR
driverWait.until(ExpectedConditions.or(
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.something")),
ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.anything"))));
Upvotes: 28
Reputation: 1305
You could use a lambda
WebDriverWait(driver,15).until(
lambda driver: driver.find_elements(By.ID,"Id1") or driver.find_elements(By.ID,"Id2"))
Upvotes: 12
Reputation: 50819
Not tested, but you can try something like
element = WebDriverWait(self.browser, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#elem1, #elem2")))
The comma in the selector is OR
.
Upvotes: 13