🐛 Частые ошибки с ожиданиями

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

⚡ Топ-6 ошибок с ожиданиями

  1. TimeoutException — элемент не появился за отведённое время. Увеличить timeout или проверить локатор.
  2. Смешивание implicit + explicit — непредсказуемые задержки. Использовать только явное.
  3. time.sleep вместо EC — медленно и ненадёжно. Заменить на WebDriverWait.
  4. presence вместо visibility — элемент найден, но скрыт, клик выбрасывает исключение.
  5. StaleElementReferenceException — DOM обновился, элемент устарел. Перенайти элемент.
  6. TimeoutException с WebDriverWait — timeout меньше реальной задержки. Для slow calculator — не менее 50 сек.

Ошибка 1: TimeoutException — элемент не появился

selenium.common.exceptions.TimeoutException: Message:
Элемент не удовлетворил условию EC за указанный timeout.
# Причина: слишком маленький timeout
wait = WebDriverWait(driver, 2)  # Только 2 секунды
button = wait.until(
    EC.presence_of_element_located((By.XPATH, "//button[text()='Button Appearing After Delay']"))
)
# Если кнопка появляется через 5 секунд — TimeoutException

# Решение: увеличить timeout
wait = WebDriverWait(driver, 15)
button = wait.until(
    EC.presence_of_element_located((By.XPATH, "//button[text()='Button Appearing After Delay']"))
)
Диагностика: если тест стабильно падает с TimeoutException, откройте страницу вручную и замерьте реальное время появления элемента. Установите timeout с запасом 20–30%.

Ошибка 2: Смешивание implicitly_wait и WebDriverWait

Использование обоих методов в одном тесте: таймауты складываются, поведение становится непредсказуемым.
# ПЛОХО: оба ожидания вместе
@pytest.fixture
def driver():
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)  # Глобальное ожидание
    yield driver
    driver.quit()

def test_example(driver):
    wait = WebDriverWait(driver, 5)  # Явное ожидание
    # Реальный timeout может быть 10+5 = 15 секунд или непредсказуемым
    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")))

Ошибка 3: time.sleep() для AJAX

Фиксированная задержка ненадёжна: медленнее нужного — потеря времени, быстрее — тест падает.
# ПЛОХО
ajax_button.click()
time.sleep(15)  # Всегда ждём 15 секунд
text_element = driver.find_element(By.CLASS_NAME, "bg-success")

# ХОРОШО
ajax_button.click()
wait.until(
    EC.text_to_be_present_in_element((By.CLASS_NAME, "bg-success"), "Data loaded")
)  # Завершится сразу после появления текста

Ошибка 4: presence вместо visibility для клика

Элемент есть в DOM, но скрыт. Клик по скрытому элементу → ElementNotInteractableException.
# ПЛОХО: presence_of_element_located находит скрытый элемент
button = wait.until(EC.presence_of_element_located((By.ID, "submit-btn")))
button.click()  # ElementNotInteractableException, если кнопка скрыта!

# ХОРОШО: element_to_be_clickable проверяет видимость и активность
button = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))
button.click()
Правило: если нужно кликнуть — используйте element_to_be_clickable. presence_of_element_located подходит только для чтения атрибутов/текста скрытых элементов.

Ошибка 5: StaleElementReferenceException

После AJAX-обновления страницы старая ссылка на элемент устаревает. Selenium выбрасывает StaleElementReferenceException.
# ПЛОХО: нашли элемент до AJAX-обновления, пытаемся использовать после
old_element = driver.find_element(By.ID, "content")
ajax_button.click()  # Страница обновляется через AJAX
old_element.text  # StaleElementReferenceException!

# ХОРОШО: найти элемент заново после обновления
ajax_button.click()
wait.until(EC.staleness_of(old_element))  # Ждём исчезновения старого элемента
new_element = wait.until(EC.visibility_of_element_located((By.ID, "content")))
print(new_element.text)

Ошибка 6: Неверный timeout для slow calculator

Для slow calculator с задержкой 45 секунд нельзя устанавливать timeout = 45 или меньше.
# ПЛОХО: timeout равен задержке — риск падения из-за задержек сети
wait = WebDriverWait(driver, 45)
result = wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".screen"), "15"))

# ХОРОШО: запас сверху
wait = WebDriverWait(driver, 50)  # 45 сек задержка + 5 сек запас
result = wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".screen"), "15"))

Ошибка 7: Не вызывать clear() перед send_keys()

# ПЛОХО: поле может содержать старое значение
field = driver.find_element(By.NAME, "username")
field.send_keys("Admin")  # Может получиться "OldValueAdmin"

# ХОРОШО
field = driver.find_element(By.NAME, "username")
field.clear()
field.send_keys("Admin")