Что такое Selenium WebDriver?
Selenium WebDriver — самый устоявшийся инструмент автоматизации браузеров, используемый миллионами тестировщиков. Он предоставляет программный интерфейс для управления браузерами через протокол W3C WebDriver.
Архитектура Selenium
Тест-код (Java/Python/JS/C#)
↓
API WebDriver
↓
Драйвер браузера (ChromeDriver, GeckoDriver)
↓
Браузер (Chrome, Firefox, Safari, Edge)
Тест-код вызывает API WebDriver, который отправляет команды драйверу конкретного браузера, управляющему реальным браузером.
Настройка Selenium
Python
pip install selenium pytest
JavaScript (WebdriverIO)
npm init -y
npm install webdriverio @wdio/cli @wdio/mocha-framework
npx wdio config
Написание первого теста
Python
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
def test_valid_login():
driver = webdriver.Chrome()
driver.get("https://app.example.com/login")
driver.find_element(By.ID, "email").send_keys("admin@test.com")
driver.find_element(By.ID, "password").send_keys("secret123")
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
wait = WebDriverWait(driver, 10)
wait.until(EC.url_contains("/dashboard"))
welcome = driver.find_element(By.CLASS_NAME, "welcome").text
assert welcome == "Welcome, Admin"
driver.quit()
Java
public class LoginTest {
WebDriver driver;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@Test
public void testValidLogin() {
driver.get("https://app.example.com/login");
driver.findElement(By.id("email")).sendKeys("admin@test.com");
driver.findElement(By.id("password")).sendKeys("secret123");
driver.findElement(By.cssSelector("button[type='submit']")).click();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.urlContains("/dashboard"));
String welcome = driver.findElement(By.className("welcome")).getText();
assertEquals(welcome, "Welcome, Admin");
}
@AfterMethod
public void teardown() { driver.quit(); }
}
Стратегии локаторов
| Стратегия | Пример | Надёжность |
|---|---|---|
By.id | By.id("email") | Высокая (если уникален) |
By.css | By.css("[data-testid='email']") | Высокая |
By.xpath | By.xpath("//input[@name='email']") | Средняя |
By.name | By.name("email") | Средняя |
By.className | By.className("input-email") | Низкая |
Лучшие практики локаторов
- Предпочитайте data-testid:
[data-testid="login-submit"] - CSS-селекторы вместо XPath — они быстрее
- Избегайте абсолютного XPath:
/html/body/div[3]/form/input[2]легко ломается - Избегайте стилевых классов:
.btn-primaryможет измениться при редизайне - Относительный XPath при необходимости:
//button[contains(text(), 'Submit')]
Ожидания
Неявное ожидание
driver.implicitly_wait(10)
Глобальный таймаут для поиска элементов. Просто, но может маскировать проблемы синхронизации.
Явное ожидание (Рекомендуется)
wait = WebDriverWait(driver, 10)
# Ожидание видимости элемента
element = wait.until(EC.visibility_of_element_located((By.ID, "dashboard")))
# Ожидание кликабельности
wait.until(EC.element_to_be_clickable((By.ID, "submit")))
# Ожидание появления текста
wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, "status"), "Complete"))
# Ожидание смены URL
wait.until(EC.url_contains("/dashboard"))
Продвинутые взаимодействия
API Actions
from selenium.webdriver import ActionChains
actions = ActionChains(driver)
# Наведение на элемент
actions.move_to_element(menu_item).perform()
# Перетаскивание
actions.drag_and_drop(source, target).perform()
# Правый клик
actions.context_click(element).perform()
# Двойной клик
actions.double_click(element).perform()
Работа с выпадающими списками
from selenium.webdriver.support.ui import Select
dropdown = Select(driver.find_element(By.ID, "country"))
dropdown.select_by_visible_text("Россия")
dropdown.select_by_value("RU")
dropdown.select_by_index(5)
Работа с алертами
alert = driver.switch_to.alert
alert_text = alert.text
alert.accept() # Нажать OK
alert.dismiss() # Нажать Отмена
alert.send_keys("текст ввода")
Работа с фреймами и окнами
# Переключение на iframe
driver.switch_to.frame("frame-name")
driver.switch_to.default_content() # Возврат на основную страницу
# Работа с новым окном/вкладкой
original_window = driver.current_window_handle
for handle in driver.window_handles:
if handle != original_window:
driver.switch_to.window(handle)
break
Скриншоты
driver.save_screenshot("screenshots/test-failure.png")
Выполнение JavaScript
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
driver.execute_script("arguments[0].click()", hidden_button)
title = driver.execute_script("return document.title")
Лучшие практики Selenium
- Всегда явные ожидания — никогда Thread.sleep()
- Закрывайте driver в teardown — предотвращайте зомби-процессы браузера
- Используйте Page Object Model — отделяйте логику от деталей страниц
- Предпочитайте CSS-селекторы — быстрее и читаемее XPath
- Headless-режим для CI —
options.add_argument("--headless") - Разумные таймауты — 10-30 секунд для явных ожиданий
- Обрабатывайте StaleElementReferenceException — перенаходите элементы при изменении DOM
Упражнение: Постройте suite тестов на Selenium
Создайте набор тестов Selenium:
- Настройте проект с Selenium + предпочитаемый язык
- Напишите класс BasePage с общими методами
- Создайте page objects для Login, Dashboard и Settings
- Напишите 5 тест-кейсов: логин, навигация, отправка формы, выбор из списка, выход
- Добавьте явные ожидания для всех динамических элементов
- Запустите тесты в режиме с интерфейсом и headless
Ключевые выводы
- Selenium WebDriver управляет браузерами через протокол W3C WebDriver
- Используйте явные ожидания (WebDriverWait) вместо Thread.sleep()
- CSS-селекторы и data-testid — лучшие стратегии локаторов
- Actions API обрабатывает сложные взаимодействия (наведение, перетаскивание, клавиатура)
- Всегда используйте Page Object Model для поддерживаемого кода
- Selenium поддерживает Java, Python, JavaScript, C#, Ruby и Kotlin