Sometimes, built-in wait conditions in Selenium do not fit your needs. Custom expected conditions let you create your own rules to wait for specific things on a webpage.
Custom expected conditions in Selenium Python
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class CustomCondition: def __init__(self, locator): self.locator = locator def __call__(self, driver): element = driver.find_element(*self.locator) # return True or element if condition met, else False or None return element if element.text == 'Expected Text' else False
Custom expected conditions are classes or functions that implement the __call__ method.
The __call__ method receives the driver and returns a truthy value when the condition is met, or False/None otherwise.
class TextIsPresent: def __init__(self, locator, text): self.locator = locator self.text = text def __call__(self, driver): element = driver.find_element(*self.locator) return element if self.text in element.text else False
def element_has_attribute(locator, attribute, value): def _predicate(driver): element = driver.find_element(*locator) return element if element.get_attribute(attribute) == value else False return _predicate
This test script opens a webpage, waits up to 10 seconds for a button with ID 'submit-button' to become enabled, then prints confirmation.
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait class ButtonEnabled: def __init__(self, locator): self.locator = locator def __call__(self, driver): button = driver.find_element(*self.locator) return button if button.is_enabled() else False # Setup driver (example with Chrome) driver = webdriver.Chrome() driver.get('https://example.com') wait = WebDriverWait(driver, 10) button_locator = (By.ID, 'submit-button') # Wait until the button is enabled button = wait.until(ButtonEnabled(button_locator)) print('Button is enabled:', button.is_enabled()) driver.quit()
Always return the element or a truthy value when the condition is met, so you can use it after waiting.
Return False or None if the condition is not met to keep waiting.
Custom conditions help make your tests more flexible and readable.
Custom expected conditions let you wait for exactly what you need on a page.
They are classes or functions with a __call__ method that Selenium calls repeatedly.
Use them to improve test reliability and clarity.
Practice
Solution
Step 1: Understand built-in expected conditions
Built-in expected conditions cover common waits like element visibility or clickability.Step 2: Identify the need for custom conditions
When a specific wait is not available, custom expected conditions let you define exactly what to wait for.Final Answer:
To wait for a specific condition that is not covered by built-in expected conditions -> Option CQuick Check:
Custom expected conditions = wait for custom needs [OK]
- Thinking custom conditions speed up browser loading
- Confusing custom conditions with browser resizing
- Assuming custom conditions generate reports
Solution
Step 1: Recall the special method for callable classes
The method __call__ makes an instance callable like a function.Step 2: Check method signature and return
The __call__ method takes driver and returns a boolean or element to wait for.Final Answer:
class MyCondition:\n def __call__(self, driver):\n return driver.title == 'Home' -> Option AQuick Check:
Custom condition class needs __call__ method [OK]
- Using call instead of __call__ method
- Defining __init__ to return a value
- Defining a function instead of a class
WebDriverWait(driver, 10).until(MyCondition()) return if the page title is 'Dashboard'?
class MyCondition:
def __call__(self, driver):
if driver.title == 'Dashboard':
return True
else:
return FalseSolution
Step 1: Understand WebDriverWait with custom condition
WebDriverWait calls the condition repeatedly until it returns a truthy value or timeout.Step 2: Analyze the condition's return value
If the title is 'Dashboard', __call__ returns True, so wait ends and returns True.Final Answer:
It will wait until the title is 'Dashboard' and then return True -> Option DQuick Check:
Condition returns True -> wait ends successfully [OK]
- Thinking it raises TimeoutException immediately
- Assuming it returns False immediately
- Confusing return value with driver object
class ElementHasText:
def __call__(self, driver):
element = driver.find_element(By.ID, 'msg')
if element.text:
return element.text
else:
return FalseSolution
Step 1: Check usage of By.ID in the code
The code uses By.ID but does not import By, causing a NameError.Step 2: Verify other parts of the code
Returning element.text is valid for expected conditions; inheritance from WebDriverWait is not required.Final Answer:
Missing import for By from selenium.webdriver.common.by -> Option AQuick Check:
Using By requires importing it first [OK]
- Assuming __call__ must return only True/False
- Thinking class must inherit WebDriverWait
- Confusing find_element with find_elements
Solution
Step 1: Understand the requirement
We want to wait until the text contains the word 'Complete' anywhere inside.Step 2: Analyze each option's condition
class StatusComplete: def __call__(self, driver): element = driver.find_element(By.ID, 'status') return 'Complete' in element.text checks if 'Complete' is in element.text, which matches the requirement exactly and returns a boolean.Step 3: Compare other options
class StatusComplete: def __call__(self, driver): element = driver.find_element(By.ID, 'status') if element.text == 'Complete': return True else: return False checks exact equality, which is too strict. class StatusComplete: def __call__(self, driver): element = driver.find_element(By.ID, 'status') return element.text.startswith('Complete') checks startswith, which is partial. class StatusComplete: def __call__(self, driver): element = driver.find_element(By.ID, 'status') return element.text != '' only checks non-empty text, which is too broad.Final Answer:
class StatusComplete:\n def __call__(self, driver):\n element = driver.find_element(By.ID, 'status')\n return 'Complete' in element.text -> Option BQuick Check:
Use 'in' to check substring presence [OK]
- Checking exact equality instead of substring
- Using startswith instead of contains
- Checking only for non-empty text
Ready to prove it?
Pass the test and this pattern moves unknown
