Modern Python Selenium frameworks have smart-waiting already included before performing actions such as clicking. For example, here's a SeleniumBase script that tests a demo e-commerce website:
from seleniumbase import SB
with SB() as sb:
sb.open("https://www.saucedemo.com/")
sb.type("input#user-name", "standard_user")
sb.type("input#password", "secret_sauce")
sb.click("input#login-button")
sb.click('button[id="add-to-cart-test.allthethings()-t-shirt-(red)"]')
sb.click("div#shopping_cart_container a")
sb.click("button#checkout")
sb.type("input#first-name", "SeleniumBase")
sb.type("input#last-name", "Rocks")
sb.type("input#postal-code", "01720")
sb.click("input#continue")
sb.click("button#finish")
sb.assert_exact_text("Thank you for your order!", "h2")
In addition, there are simple methods for waiting for certain things if you still want to use those. Eg:
sb.wait_for_element_present(selector)
sb.wait_for_element_visible(selector)
sb.wait_for_element_clickable(selector)
(The selector
is auto-detected, which means you no longer have to specify CSS vs XPath.)
The Selenium "best practices" now recommend using frameworks that include smart-waiting for you:
That means NOT USING a long line like this anymore:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button"))).click()
and instead, DO USE a framework where you can do something like this:
sb.click("button")
It's much cleaner, just as reliable, and displays better error messages if the element you're looking for never shows up within the default timeout.
Frameworks, such as SeleniumBase, are listed on the Selenium Ecosystem page: https://www.selenium.dev/ecosystem/#frameworks