⚖️ Старый vs Новый: ожидания в Selenium
⚡ Коротко о миграции
time.sleep(N)→WebDriverWait(driver, N).until(EC.xxx(...))implicitly_waitдля AJAX → явное ожидание конкретного состояния- Смешивание implicit + explicit → только явное ожидание
Антипаттерн 1: time.sleep() вместо явного ожидания
Из лекции (старое):
time.sleep() используется для ожидания AJAX-ответа. Это жёсткое ожидание — тест ждёт фиксированное время независимо от реального состояния страницы.
Из лекции (антипаттерн)
# test_ajax_old.py — АНТИПАТТЕРН
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
@pytest.fixture
def driver():
driver = webdriver.Chrome()
driver.get("https://example.com")
yield driver
driver.quit()
def test_ajax_request_sleep(driver):
ajax_button = driver.find_element(By.ID, "ajaxButton")
ajax_button.click()
# Жёсткое ожидание 15 секунд (плохая практика)
time.sleep(15)
ajax_text_element = driver.find_element(By.CLASS_NAME, "bg-success")
assert "Data loaded with AJAX get request." in ajax_text_element.text
Современный подход (Selenium 4)
# test_ajax_new.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
@pytest.fixture
def driver():
driver = webdriver.Chrome()
driver.get("https://example.com")
yield driver
driver.quit()
def test_ajax_request(driver):
wait = WebDriverWait(driver, 15)
driver.find_element(By.ID, "ajaxButton").click()
# Ждём конкретного текста — без лишних задержек
result = wait.until(
EC.text_to_be_present_in_element(
(By.CLASS_NAME, "bg-success"),
"Data loaded with AJAX get request."
)
)
assert result, "Текст AJAX-ответа не появился!"
| time.sleep(15) | WebDriverWait + EC | |
|---|---|---|
| Скорость | Всегда 15 секунд | Сразу после появления текста |
| Надёжность | Упадёт, если страница медленнее | Ждёт до max timeout |
| Читаемость | Неочевидно, зачем пауза | Явно — что и почему ждём |
Антипаттерн 2: implicitly_wait для AJAX
Из лекции (менее надёжный вариант): использование только
implicitly_wait для AJAX. Он ждёт появления элемента в DOM, но не конкретного состояния (текста, URL, кликабельности).
Из лекции (менее надёжный вариант)
# test_ajax_implicit.py — менее надёжный вариант
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
@pytest.fixture
def driver():
driver = webdriver.Chrome()
driver.implicitly_wait(15) # Глобальное неявное ожидание
driver.get("https://example.com")
yield driver
driver.quit()
def test_ajax_request_implicit(driver):
driver.find_element(By.ID, "ajaxButton").click()
# Selenium ждёт до 15 секунд появления элемента
ajax_text_element = driver.find_element(By.CLASS_NAME, "bg-success")
assert "Data loaded with AJAX get request." in ajax_text_element.text
Проблема
Элемент .bg-success может появиться в DOM раньше, чем сервер вернёт нужный текст. implicitly_wait не умеет ждать конкретного содержимого — он видит элемент и сразу возвращает его. Текст внутри может оказаться пустым или с другим значением.
Современный подход (Selenium 4)
# test_ajax_explicit.py — рекомендуется
def test_ajax_request(driver):
wait = WebDriverWait(driver, 15)
driver.find_element(By.ID, "ajaxButton").click()
# Явно ждём конкретный текст внутри элемента
result = wait.until(
EC.text_to_be_present_in_element(
(By.CLASS_NAME, "bg-success"),
"Data loaded with AJAX get request."
)
)
assert result
Антипаттерн 3: смешивание implicit + explicit
Использование
driver.implicitly_wait() вместе с WebDriverWait в одном тесте приводит к непредсказуемому поведению: их таймауты суммируются, и реальное время ожидания становится неочевидным.
# ПЛОХО: implicit + explicit вместе
driver.implicitly_wait(10) # Глобально
def test_example(driver):
wait = WebDriverWait(driver, 5) # Явное: до 5 секунд
# Но элемент может ждать до 10+5 = непредсказуемо!
element = wait.until(EC.presence_of_element_located((By.ID, "btn")))
# ХОРОШО: только явное ожидание
@pytest.fixture
def driver():
driver = webdriver.Chrome()
# Не устанавливаем implicitly_wait
yield driver
driver.quit()
def test_example(driver):
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, "btn")))