🐛 Типичные ошибки — Ожидания в Selenium

← К оглавлению урока

⚡ Топ-3 ошибки

  1. TimeoutException — таймаут слишком мал или EC не то
  2. presence vs visibility — элемент в DOM, но не виден
  3. Смешивание implicit + explicit — непредсказуемые задержки

Ошибка 1. TimeoutException — истёк таймаут ожидания

Симптом

selenium.common.exceptions.TimeoutException: Message: 

Причины и исправление

ПричинаРешение
Таймаут слишком малУвеличьте таймаут: для slow calculator — 50 сек
Неправильный локаторПроверьте локатор в DevTools браузера
Не то условие ECНапример, ждёте visibility, а элемент в DOM но скрыт — используйте presence
Страница измениласьПроверьте, что тестовый сайт доступен и не изменил DOM

Ошибка 2. presence vs visibility — неправильный выбор EC

Проблема

# НЕПРАВИЛЬНО: ждём visibility, но элемент скрыт (display:none)
element = wait.until(EC.visibility_of_element_located((By.ID, "hidden-input")))
# TimeoutException — элемент в DOM, но не виден

Исправление

# ПРАВИЛЬНО: для скрытых элементов — presence
element = wait.until(EC.presence_of_element_located((By.ID, "hidden-input")))

# Для кнопок, которые нужно нажать — clickable
button = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))

Запомните разницу:

  • presence — элемент существует в DOM (может быть display:none)
  • visibility — элемент виден пользователю (не скрыт, не за экраном)
  • clickable — виден И включён (не disabled)

Ошибка 3. Смешивание implicitly_wait и WebDriverWait

Проблема

# ПЛОХО: оба типа ожиданий активны одновременно
driver.implicitly_wait(10)
wait = WebDriverWait(driver, 10)

# Поведение непредсказуемо: задержки могут суммироваться или конфликтовать
element = wait.until(EC.presence_of_element_located((By.ID, "some-id")))

Исправление

# ПРАВИЛЬНО: используйте только один подход
# Вариант 1 — только WebDriverWait + EC (рекомендуется)
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, "some-id")))

# Вариант 2 — только implicitly_wait (для простых случаев)
driver.implicitly_wait(10)
element = driver.find_element(By.ID, "some-id")

Ошибка 4. StaleElementReferenceException

Симптом

selenium.common.exceptions.StaleElementReferenceException:
  Message: stale element reference: element is not attached to the page document

Причина

Элемент был найден, потом страница обновилась (AJAX-запрос перерисовал DOM), и ссылка на элемент устарела.

Исправление

# НЕПРАВИЛЬНО: находим элемент, затем страница обновляется — элемент устарел
button = driver.find_element(By.ID, "ajaxButton")
button.click()
# ...AJAX запрос обновляет DOM...
old_element = driver.find_element(By.ID, "some-dynamic-element")
wait.until(EC.staleness_of(old_element))
old_element.click()  # StaleElementReferenceException!

# ПРАВИЛЬНО: находим элемент ПОСЛЕ обновления DOM
button = driver.find_element(By.ID, "ajaxButton")
button.click()
# Ждём обновления DOM
wait.until(EC.text_to_be_present_in_element((By.ID, "result"), "loaded"))
# Находим элемент заново
new_element = driver.find_element(By.ID, "some-dynamic-element")
new_element.click()

Ошибка 5. Забыть clear() перед send_keys()

Проблема

# НЕПРАВИЛЬНО: поле уже содержит "5", вводим "45" → получаем "545"
delay_input = driver.find_element(By.CSS_SELECTOR, "#delay")
delay_input.send_keys("45")  # Вместо "45" в поле будет "545"!

Исправление

# ПРАВИЛЬНО: сначала очистить поле
delay_input = driver.find_element(By.CSS_SELECTOR, "#delay")
delay_input.clear()       # Сбрасываем существующее значение
delay_input.send_keys("45")  # Вводим нужное значение

Ошибка 6. time.sleep вместо явного ожидания

Проблема

# НЕПРАВИЛЬНО: жёсткое ожидание
import time

driver.find_element(By.ID, "ajaxButton").click()
time.sleep(15)  # Ждём 15 секунд — даже если ответ пришёл через 2 сек
element = driver.find_element(By.CLASS_NAME, "bg-success")

Исправление

# ПРАВИЛЬНО: явное ожидание завершается как только условие выполнено
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver.find_element(By.ID, "ajaxButton").click()
wait = WebDriverWait(driver, 15)
wait.until(
    EC.text_to_be_present_in_element(
        (By.CLASS_NAME, "bg-success"), "Data loaded"
    )
)

Ошибка 7. Неправильный таймаут для slow calculator

Проблема

# НЕПРАВИЛЬНО: задержка 45 сек, но таймаут только 10 сек
delay_input.send_keys("45")
# ...
wait = WebDriverWait(driver, 10)  # TimeoutException через 10 сек!

Исправление

# ПРАВИЛЬНО: таймаут должен быть БОЛЬШЕ задержки
delay_input.send_keys("45")
# ...
wait = WebDriverWait(driver, 50)  # 45 сек задержки + 5 сек запас