🔖 Справочник — Ожидания и 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_containsURL содержит подстрокуTrue/False
title_containsЗаголовок страницы содержит текстTrue/False
frame_to_be_available_and_switch_to_itiframe доступен + переключается в негоTrue/False
alert_is_presentПоявился JavaScript-alertAlert object
staleness_ofЭлемент удалён из DOMTrue/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()