🔖 Справочник — Ожидания и EC в Selenium 4
⚡ Быстрый старт
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.ID, "btn"))).click()
Импорты
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
WebDriverWait — создание объекта ожидания
# Синтаксис
wait = WebDriverWait(driver, timeout)
wait = WebDriverWait(driver, timeout, poll_frequency=0.5) # интервал опроса в сек
wait = WebDriverWait(driver, timeout, ignored_exceptions=[...]) # игнорируемые исключения
# Примеры
wait = WebDriverWait(driver, 10) # ждать до 10 секунд
wait = WebDriverWait(driver, 15) # ждать до 15 секунд (для медленных страниц)
wait = WebDriverWait(driver, 50) # для очень медленных операций (slow calculator)
Expected Conditions — шпаргалка
| Условие EC | Что ждёт | Возвращает |
|---|---|---|
presence_of_element_located | Элемент появился в DOM (может быть скрыт) | WebElement |
visibility_of_element_located | Элемент в DOM и виден пользователю | WebElement |
element_to_be_clickable | Элемент виден и включён (enabled) | WebElement |
text_to_be_present_in_element | Нужный текст появился внутри элемента | True/False |
url_contains | URL содержит подстроку | True/False |
title_contains | Заголовок страницы содержит текст | True/False |
frame_to_be_available_and_switch_to_it | iframe доступен + переключается в него | True/False |
alert_is_present | Появился JavaScript-alert | Alert object |
staleness_of | Элемент удалён из DOM | True/False |
element_located_to_be_selected | Чекбокс/radio выбран | True/False |
Примеры синтаксиса для каждого EC
# test_ec_examples.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
# presence — элемент в DOM (может быть скрыт)
element = wait.until(EC.presence_of_element_located((By.ID, "element_id")))
# visibility — элемент виден
element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "visible-element")))
# clickable — элемент кликабелен
button = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Submit']")))
button.click()
# text в элементе
wait.until(EC.text_to_be_present_in_element((By.TAG_NAME, "h1"), "Dashboard"))
# URL содержит подстроку
wait.until(EC.url_contains("dashboard"))
# title страницы содержит текст
wait.until(EC.title_contains("Dashboard"))
# iframe доступен и переключиться в него
wait.until(EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe")))
# JavaScript alert появился
alert = wait.until(EC.alert_is_present())
alert.accept() # подтвердить
# alert.dismiss() # отклонить
# Элемент устарел (удалён из DOM)
old_element = driver.find_element(By.ID, "old-element")
wait.until(EC.staleness_of(old_element))
# Чекбокс / radio выбран
wait.until(EC.element_located_to_be_selected((By.NAME, "checkbox")))
Взаимодействие с элементами
# test_interactions.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Ввод текста
field = driver.find_element(By.NAME, "username")
field.send_keys("Admin")
# Очистка поля и ввод нового значения
field = driver.find_element(By.CSS_SELECTOR, "#delay")
field.clear()
field.send_keys("45")
# Клик (предпочтительно через element_to_be_clickable)
button = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[@type='submit']")))
button.click()
# Получение атрибута элемента
img = driver.find_element(By.CSS_SELECTOR, "img:nth-of-type(3)")
alt_value = img.get_attribute("alt")
# Получение CSS-класса элемента (для проверки валидации)
field = driver.find_element(By.NAME, "zip-code")
classes = field.get_attribute("class")
assert "is-invalid" in classes
Неявные ожидания
# conftest.py
import pytest
from selenium import webdriver
@pytest.fixture
def driver():
driver = webdriver.Chrome()
driver.implicitly_wait(10) # Глобально: ждать до 10 сек при каждом find_element
yield driver
driver.quit()
Важно: не смешивайте implicitly_wait и WebDriverWait в одном тесте. Их взаимодействие непредсказуемо и может давать неожиданные задержки.
Типовая структура pytest-теста с явным ожиданием
# test_typical.py
import pytest
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
@pytest.fixture
def driver():
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://example.com")
yield driver
driver.quit()
def test_something(driver):
wait = WebDriverWait(driver, 10)
# Ожидаем нужное состояние
element = wait.until(EC.element_to_be_clickable((By.ID, "my-button")))
element.click()
# Проверяем результат
result = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".result")))
assert result.is_displayed()