13

I have trouble understanding how to use an 'expected conditions' to check for the presence of an element. Given this documentation it is not clear at all how to use this. I have tried the following code

 def _kernel_is_idle(self):
    return EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]'))

with the idea of checking an element (callable as a method within a class). There are two things that do not make any sense:

  1. According to the documentation (I had to look up the source code!), this method should return either True or False. However, it returns the following:

    <selenium.webdriver.support.expected_conditions.visibility_of_element_located object at 0x110321b90>
    
  2. How can this function work without a webdriver? Usually you always have a call like

    driver.do_something()
    

but where is the referece to the webdriver for an 'expected condition'?

Alex
  • 41,580
  • 88
  • 260
  • 469
  • Can you explain why do you need such kind of method instead of just using common built-in Selenium methods and properties? – Andersson Dec 13 '17 at 10:12
  • Yes maybe. Do the common built-in selenium methods return `False` in case an element is not there? Like `driver.find_elements(By.XPATH, '//button')`? Or do I have to do `try/except`? – Alex Dec 13 '17 at 10:18
  • `visibility_of_element_located` intend to check whether element is visible. Tha same you can try to do with `driver.find_element(By.XPATH, '//button').is_displayed()`. If you want to check presence of element you can try `bool(driver.find_elements(By.XPATH, '//button'))` – Andersson Dec 13 '17 at 10:30

5 Answers5

10

To summarize in a more organized manner:

  • Expected Condition is a callable (could be a function or a class with __call__() magic method defined)
  • Expected Condition is supposed to be used inside the until() method of a WebDriverWait() instance:

    wait = WebDriverWait(driver, 10)
    wait.until(<Expected_condition_here>)
    
  • the result of an Expected Condition does not have to be just True/False. The result would be tested on truthiness by the WebDriverWait. Note: a WebElement instance is "truthy". Read more about truthiness in Python here

  • it is quite convenient that when an Expected Condition returns a WebElement instance. It allows to have a link to an element right away without the need to find it again:

    button = wait.until(EC.element_to_be_clickable((By.ID, "my_id")))
    button.click()
    
  • you can write your own custom Expected Conditions
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
7

Seems you were almost there.

The Documentation clearly says the following:

class selenium.webdriver.support.expected_conditions.visibility_of_element_located(locator)

Which is defined as :

An expectation for checking that an element is present on the DOM of a page and visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0. locator - used to find the element returns the WebElement once it is located and visible

Hence, when you mention:

return EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]'))

The found out WebElement is being returned as follows :

<selenium.webdriver.support.expected_conditions.visibility_of_element_located object at 0x110321b90>

Even the Source Code says the same as :

try:
    return _element_if_visible(_find_element(driver, self.locator))

When the search is unsuccessfull :

except StaleElementReferenceException:
    return False
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • 2
    `` is not a WebElement, but just an instance of `visibility_of_element_located()` class. To get WebElement it should be called as `EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]'))(driver)` – Andersson Dec 13 '17 at 12:56
  • Unless we cast the `driver` instance and invoke the `EC`, we shouldn't expect the `WebElement` anyway, right? We would see the instance only. – undetected Selenium Dec 13 '17 at 12:59
  • Yes, in the way OP use it (`return EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]'))`) we will not get WebElement – Andersson Dec 13 '17 at 13:05
  • That's right. But the way OP invoked EC what ever he is seeing is pretty correct. – undetected Selenium Dec 13 '17 at 13:06
2

The way expected conditions work is by defining a WebDriverWait. You create this with an instance of your WebDriver and a timeout. The WebDriverWait has an until() method which will take an expected condition and will wait until it has been met or until the timeout has passed. So instead of just EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]')) you should use:

WebDriverWait(yourdriver, timeout).until(EC.visibility_of_element_located((By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]')))

Edit I should note that this doesn't return True or False. This will return the WebElement if it has been found and is visible. Otherwise it will raise a TimeOutException. Source

RemcoW
  • 4,196
  • 1
  • 22
  • 37
2

You're almost success! What you want could be:

def _kernel_is_idle(self):
    return EC.visibility_of_element_located(
        (By.XPATH, '//*[@id="kernel_indicator_icon" and @title="Kernel Idle"]')
    )(driver)

Here, you should pass the webdriver object as an argument.

Nianliang
  • 2,926
  • 3
  • 29
  • 22
1

First you need to import expected_conditions module from selenium.webdriver.support. With this module you can check several conditions of the element with giving expected time as well

from selenium import webdriver
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("http://domain/element")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "idxxx"))
    )
finally:
    driver.quit()
Soumya
  • 187
  • 1
  • 6