⚖️ Старый 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")))