'Selenium Combining multiple Expected conditions in Python

wait = (driver, 10)
wait.until(EC.presence_of_element_located((By.XPATH, '//td[@class="blah blah blah"]')))
wait.until(EC.visibility_of_element_located((By.XPATH, '//h1[text() = "yo yo"]')))

Is there a way to combine these two conditions into one line or any way that says if both of these conditions are true then only click() in Selenium, Python.



Solution 1:[1]

Here's an example of making a function for Selenium's WebDriverWait:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

# Open the website
driver.get('https://ocrdata.ed.gov/flex/Reports.aspx?type=school')

... more code ...

# Custom function for Explicit Wait
# The Export button is available before it is "clickable", need to wait
def find(driver):
    export_button = driver.find_element_by_name('ctl00$div$ucReportViewer$btnExport')
    if export_button:
        try: 
            export_button.click()
            return True
        except:
            return False
    else:
        return False

secs = 120
export_button = WebDriverWait(driver, secs).until(find)

I would suggest recording the presence and visibility of both elements as separate variables and creating an if statement in the function like so:

# Custom function for Explicit Wait
# The Export button is available before it is "clickable", need to wait
def find(driver):
    presence = EC.presence_of_element_located((By.XPATH, '//td[@class="blah blah blah"]'))
    visibility = EC.visibility_of_element_located((By.XPATH, '//h1[text() = "yo yo"]'))
    if presence and visibility:
        try: 
            # action
            return True
        except:
            return False
    else:
        return False

secs = 120
export_button = WebDriverWait(driver, secs).until(find)

Solution 2:[2]

I was having the same problem and found an answer! You can use EC.all_of(*expected_conditions) to check for multiple Expected Conditions, just like logical AND, or EC.any_of(*expected_conditions) to check for logical OR.

So the code would be something like this:

WebDriverWait(driver, 5).until(
    EC.all_of(
        EC.presence_of_element_located((By.ID, "Example")),
        EC.visibility_of_element_located((By.ID, "Example"))
    )
)

It returns a list of webdriver elements, so if you want to click an element, you'll have to select it by index, adding [i].click() to the end.

That also means if you want to click a third element outside the ones that you are checking for, you also have to add it to the check, and select it as well. At the end it would be like this:

WebDriverWait(driver, 5).until(
    EC.all_of(
        EC.presence_of_element_located((By.ID, "Example")),
        EC.visibility_of_element_located((By.ID, "Example")),
        EC.presence_of_element_located((By.ID, "Clickable"))
    )
)[2].click()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 webb
Solution 2 Dharman