apadana
apadana

Reputation: 14640

Selenium wait until one of the two elements is present

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

Answers (7)

pppery
pppery

Reputation: 3804

From a suggested edit:

Selenium 4

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

BehRouz
BehRouz

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

Harshana
Harshana

Reputation: 5476

You can use the any_of method which is implemented inside the ExpectedConditionssection 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

BachT
BachT

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

You can do an OR

driverWait.until(ExpectedConditions.or(
    ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.something")),
    ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.anything"))));

Upvotes: 28

Maeda
Maeda

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

Guy
Guy

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

Related Questions