⚖️ Старый vs Новый подход

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

⚡ Кратко

  • Alert: Старое — time.sleepswitch_to.alert. Новое — wait.until(EC.alert_is_present())
  • Вкладки: Старое — угадывать индекс из window_handles[1]. Новое — сравнение с current_window_handle
  • ActionChains: Старое — .click(element).perform() каждый раз. Новое — цепочка .move_to_element().click().perform()
  • iframe: Старое — switch_to.frame(0) (ненадёжный индекс). Новое — switch_to.frame(WebElement)

1. Alert: ожидание появления

Старый подход (из лекции)

# test_alert_old.py
import time

# Жёсткое ожидание — антипаттерн
time.sleep(3)
alert = driver.switch_to.alert
alert.accept()
  • Тест медленный: всегда ждёт 3 секунды
  • Нестабильный: на медленной машине alert может ещё не появиться
  • Нет обработки — если alert не появится, тест упадёт с непонятной ошибкой

Современный подход (Selenium 4)

# test_alert_new.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
# Ждём до 10 секунд, срабатывает сразу как alert появился
alert = wait.until(EC.alert_is_present())
alert.accept()
  • Тест быстрый: срабатывает сразу после появления alert
  • Надёжный: явный таймаут и понятное исключение (TimeoutException)
  • Возвращает объект alert напрямую

2. Переключение на новую вкладку

Старый подход

# test_tabs_old.py
# Предположение, что новая вкладка — индекс 1
# Если вкладок больше или порядок изменился — падает
driver.switch_to.window(driver.window_handles[1])
  • Хрупко: предполагаем фиксированный индекс
  • Если открыто больше 2 вкладок — нужная может быть не [1]

Современный подход (Selenium 4)

# test_tabs_new.py
# Запоминаем текущую вкладку
original = driver.current_window_handle

# ... действие открывает новую вкладку ...

# Ищем именно новую вкладку
new_tab = [h for h in driver.window_handles if h != original][0]
driver.switch_to.window(new_tab)
  • Работает независимо от количества вкладок
  • Явно определяем «новую» вкладку через разницу множеств
  • Безопасно при параллельном открытии нескольких вкладок

3. ActionChains: создание объекта

Старый подход

# test_actions_old.py
# Создаём новый ActionChains для каждого действия
ActionChains(driver).move_to_element(el1).perform()
ActionChains(driver).move_to_element(el2).perform()
ActionChains(driver).click(el3).perform()
  • Три отдельных объекта — три отдельных действия
  • Избыточно; нет накопления в цепочку

Современный подход (Selenium 4)

# test_actions_new.py
# Один объект, цепочка действий
actions = ActionChains(driver)
actions.move_to_element(el1)
actions.move_to_element(el2)
actions.click(el3)
actions.perform()    # Выполняем всё одним вызовом
  • Один объект переиспользуется
  • Цепочка выполняется как единое действие — меньше гонок
  • Удобнее читать и расширять

4. Работа с iframe: выбор фрейма

Старый подход

# test_iframe_old.py
# Переключение по индексу
driver.switch_to.frame(0)

# Переключение по имени/id как строка — без проверки существования
driver.switch_to.frame("myFrame")
  • Индекс хрупок: изменится порядок фреймов — тест упадёт
  • Нет ожидания: если iframe загружается медленно — NoSuchFrameException

Современный подход (Selenium 4)

# test_iframe_new.py
from selenium.webdriver.support import expected_conditions as EC

# Ждём появления iframe и переключаемся по WebElement
wait = WebDriverWait(driver, 10)
iframe = wait.until(
    EC.presence_of_element_located((By.TAG_NAME, "iframe"))
)
driver.switch_to.frame(iframe)

# ... работаем внутри ...

# Обязательно возвращаемся
driver.switch_to.default_content()
  • WebElement устойчив к изменению порядка фреймов
  • Ожидание через EC гарантирует, что iframe уже загружен
  • Явный возврат через default_content()

5. Загрузка файла: путь к файлу

Старый подход

# test_upload_old.py
# Жёстко заданный путь — не работает на другой машине
file_input.send_keys("C:\\Users\\user\\test.txt")

# Относительный путь — зависит от текущей директории запуска
file_input.send_keys("test.txt")
  • Жёсткий путь: тест не работает у другого разработчика
  • Относительный путь: зависит от того, откуда запущен pytest

Современный подход (Selenium 4)

# test_upload_new.py
import os

# os.path.abspath строит абсолютный путь от текущей директории
file_path = os.path.abspath("test_file.txt")
file_input.send_keys(file_path)

# Ещё надёжнее — путь относительно файла теста:
base_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_dir, "test_file.txt")
file_input.send_keys(file_path)
  • os.path.abspath() работает на любой ОС
  • Путь через __file__ не зависит от рабочей директории pytest
  • Не нужно экранировать слэши вручную