📖 Теория — Расширенные практики Selenium (часть 2)
⚡ Кратко
Alert вне DOM — работа только через switch_to.alert. Вкладки управляются через window_handles + switch_to.window(). Сложные действия мыши — ActionChains. Содержимое iframe недоступно без switch_to.frame(). Файл загружается через send_keys(abs_path) на input[type=file].
1. Alert — всплывающие диалоговые окна
Alert — это браузерное диалоговое окно, которое не является частью DOM-дерева. Обычные методы поиска элементов (find_element) его не видят. Чтобы взаимодействовать с Alert, нужно переключиться на него через switch_to.alert.
В браузере существует три типа Alert-диалогов:
- alert() — информационное окно с кнопкой «OK»
- confirm() — окно с кнопками «OK» и «Cancel»
- prompt() — окно с полем ввода текста и кнопками «OK» / «Cancel»
Методы Alert в Selenium 4
Получение текста из Alert
# test_alert.py
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://example.com/page-with-alert")
# Дожидаемся появления alert (надёжнее, чем сразу switch_to)
wait = WebDriverWait(driver, 10)
alert = wait.until(EC.alert_is_present())
text = alert.text # Получаем текст
print(text)
Принятие (OK) — alert.accept()
Нажимает «OK» в любом типе диалога:
# test_alert.py
alert.accept()
Отмена (Cancel) — alert.dismiss()
Работает только для confirm и prompt. Аналог кнопки «Отмена»:
# test_alert.py
alert.dismiss()
Ввод текста в prompt — alert.send_keys()
Доступен только для prompt()-диалогов, где есть поле ввода:
# test_alert.py
alert.send_keys("Мой ответ")
alert.accept() # Подтверждаем ввод
WebDriverWait + EC.alert_is_present() перед обращением к alert. Без ожидания тест упадёт с NoAlertPresentException, если диалог ещё не появился.
2. Переключение между вкладками и окнами
Когда страница открывает новую вкладку или окно, Selenium не переключается на неё автоматически. Нужно самостоятельно получить идентификатор новой вкладки и переключиться на неё.
Ключевые свойства и методы
driver.window_handles
Возвращает список идентификаторов всех открытых вкладок. Каждый идентификатор — уникальная строка вида 'CDwindow-XXXXXXXX':
# test_tabs.py
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
# Открываем новую вкладку через JavaScript
driver.execute_script("window.open('https://google.com', '_blank');")
# Получаем список всех вкладок
tabs = driver.window_handles
print(tabs)
# ['CDwindow-123456', 'CDwindow-789012']
driver.current_window_handle
Возвращает идентификатор текущей активной вкладки:
# test_tabs.py
print(driver.current_window_handle)
# 'CDwindow-123456'
driver.switch_to.window(handle)
Переключает Selenium на указанную вкладку:
# test_tabs.py
# Переключаемся на вторую вкладку
driver.switch_to.window(tabs[1])
# Работаем на второй вкладке...
# Закрываем вторую вкладку
driver.close()
# Обязательно переключаемся обратно!
driver.switch_to.window(tabs[0])
driver.close() активная вкладка закрыта, но Selenium всё ещё «смотрит» на неё. Любое действие вызовет ошибку. Всегда вызывайте switch_to.window() после закрытия вкладки.
3. ActionChains — сложные взаимодействия мышью
Класс ActionChains эмулирует действия пользователя, которые нельзя выполнить простым .click(): наведение курсора, двойной клик, drag&drop, контекстное меню и цепочки действий.
Паттерн использования
# test_actions.py
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
# Добавляем действия в цепочку...
actions.move_to_element(element).perform()
# perform() — выполнить всю цепочку
Hover (наведение курсора)
Используется для открытия выпадающих меню, tooltip-ов, скрытых элементов, которые появляются только при наведении:
# test_hover.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
# Наводим курсор на элемент меню
menu_item = driver.find_element(By.ID, "menu")
actions = ActionChains(driver)
actions.move_to_element(menu_item).perform()
# После hover кликаем по появившемуся подменю
submenu = driver.find_element(By.ID, "submenu")
submenu.click()
Drag and Drop (перетаскивание)
Метод drag_and_drop(source, target) перемещает элемент source на позицию target:
# test_drag_drop.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com/drag")
source = driver.find_element(By.ID, "draggable")
target = driver.find_element(By.ID, "droppable")
actions = ActionChains(driver)
actions.drag_and_drop(source, target).perform()
drag_and_drop(). В таких случаях используют drag_and_drop_by_offset() или JS-inject.
4. Работа с фреймами (iframe)
Фрейм (iframe) — это HTML-элемент, который встраивает одну страницу в другую. Элементы внутри iframe находятся в отдельном контексте DOM и недоступны напрямую. Для работы с ними нужно сначала переключиться в этот контекст.
Переключение в iframe
# test_iframe.py
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/page-with-iframe")
# Найти iframe-элемент и переключиться в него
iframe = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe)
# Теперь можно работать с элементами внутри iframe
content = driver.find_element(By.ID, "inside-iframe")
print(content.text)
# Вернуться в основной контекст страницы
driver.switch_to.default_content()
Можно переключаться по имени, индексу или WebElement:
# test_iframe.py
driver.switch_to.frame("frame-name") # по атрибуту name
driver.switch_to.frame(0) # по индексу (первый фрейм)
driver.switch_to.frame(iframe_element) # по WebElement (рекомендуется)
driver.switch_to.default_content() после работы с iframe, чтобы вернуться к основной странице. Иначе все последующие поиски элементов будут ограничены контекстом последнего фрейма.
5. Загрузка файлов
Для загрузки файла в тесте не нужно открывать системный диалог выбора файла. Selenium позволяет передать абсолютный путь к файлу напрямую в элемент <input type="file"> через send_keys().
# test_upload.py
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("http://example.com/upload")
# Получаем абсолютный путь к файлу
file_path = os.path.abspath("test_file.txt")
# Передаём путь в input[type=file]
file_input = driver.find_element(By.ID, "file-upload")
file_input.send_keys(file_path)
# Отправляем форму
driver.find_element(By.ID, "submit").click()
send_keys() работает только с нативным <input type="file">. Если кнопка загрузки кастомная (div, button, styled-input), потребуется сделать элемент видимым через JavaScript или использовать другой подход.
file_path = r"C:\Users\user\test_file.txt"Удобнее использовать
os.path.abspath() — он автоматически строит корректный путь для текущей ОС.