22

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"      
apadana
  • 11,650
  • 10
  • 73
  • 95

4 Answers4

24

You can do an OR

driverWait.until(ExpectedConditions.or(
    ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.something")),
    ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.anything"))));
undetected Selenium
  • 151,581
  • 34
  • 225
  • 281
  • 4
    tried it, gave me a syntax error at `or`, is it possible that there's no `or` method – Dariopnc Dec 27 '21 at 09:16
  • 1
    I had the same issue as @Dariopnc and this helped me https://stackoverflow.com/questions/16462177/selenium-expected-conditions-possible-to-use-or – Neox Apr 11 '22 at 06:34
  • Please note that this syntax has been released in selenium 4 – Dariopnc Apr 12 '22 at 07:29
12

You could use a lambda

WebDriverWait(driver,15).until(
    lambda driver: driver.find_elements(By.ID,"Id1") or driver.find_elements(By.ID,"Id2"))
Maeda
  • 1,245
  • 14
  • 16
  • 1
    Be careful if you ALSO use implicitly_wait(n). Each of the lambdas will take n secs before they return. So, if you had called implicitly_wait(15) and then tried WebDriverWait(driver,15).until(), then only the first lambda would be checked. – SoloPilot Nov 02 '19 at 13:40
11

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.

Guy
  • 40,130
  • 10
  • 33
  • 74
0

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
BachT
  • 1,064
  • 9
  • 17