When browser navigates to a dynamic page (most commonly AJAX-based web application), the elements on the page can take different time to load, and furthermore: some elements will only load in response to some user actions. In such cases direct retrieval of an element may fail:
# Don't do this: may fail on dynamic page with ElementNotVisibleException
element = driver.find_element_by_name('q')
The most obvious solution it seems to introduce the wait before retrieving elements:
# Don't do this: inefficient solution for ElementNotVisibleException
time.sleep(5) # delays for 5 seconds
element = driver.find_element_by_name('q')
But such solution is inefficient, since it causes the test to always wait for 5 seconds, even when the element in most cases appears after 1 second (and only sometimes requires up to 5 seconds). It doesn't look much if it's one place, but usually each test deals with multiple elements, and there are multiple tests, which adds up to overall test duration.
A better solution is to wait for element to appear for up to 5 seconds, but return from the wait as soon as element is found. WebDriverWait
allows you to do just that.
The following example navigates to www.google.com, waits (for up to 5 seconds) for the search bar to load, and then searches for "selenium".
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
# Create a new chromedriver instance
driver = webdriver.Chrome()
# Go to www.google.com
driver.get("https://www.google.com")
try:
# Wait as long as required, or maximum of 5 sec for element to appear
# If successful, retrieves the element
element = WebDriverWait(driver,5).until(
EC.presence_of_element_located((By.NAME, "q")))
# Type "selenium"
element.send_keys("selenium")
#Type Enter
element.send_keys(Keys.ENTER)
except TimeoutException:
print("Failed to load search bar at www.google.com")
finally:
driver.quit()