💻 Примеры — Явные ожидания в Selenium 4

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

⚡ Ключевые примеры

AJAX-тест с явным ожиданием, авторизация OrangeHRM, slow calculator, form validation — все с WebDriverWait + EC.

Пример 1. Базовый тест с явным ожиданием

Простой тест, демонстрирующий разницу между implicitly_wait и WebDriverWait + EC.

# test_basic_wait.py
import pytest
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


@pytest.fixture
def driver():
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)  # Неявное ожидание (только для базового поиска)
    yield driver
    driver.quit()


def test_explicit_wait_example(driver):
    driver.get("https://example.com")

    # Явное ожидание — ждём видимости конкретного элемента
    wait = WebDriverWait(driver, 10)
    element = wait.until(EC.visibility_of_element_located((By.ID, "some_id")))

    assert element.is_displayed(), "Элемент не найден!"

Пример 2. AJAX-тест с явным ожиданием

Страница: uitestingplayground.com/ajax
Кнопка "Button Triggering AJAX Request" загружает данные без перезагрузки страницы. Нужно дождаться появления текста ответа.

# test_ajax_explicit.py
import pytest
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


@pytest.fixture
def driver():
    driver = webdriver.Chrome()
    driver.get("http://www.uitestingplayground.com/ajax")
    yield driver
    driver.quit()


def test_ajax_request(driver):
    wait = WebDriverWait(driver, 15)  # Ожидание до 15 секунд

    # Нажимаем на кнопку, которая запускает AJAX-запрос
    ajax_button = driver.find_element(By.ID, "ajaxButton")
    ajax_button.click()

    # Ожидаем, пока появится элемент с классом "bg-success" и нужным текстом
    ajax_text = wait.until(
        EC.text_to_be_present_in_element(
            (By.CLASS_NAME, "bg-success"), "Data loaded with AJAX get request."
        )
    )

    # Проверяем, что текст появился
    assert ajax_text, "Текст 'Data loaded with AJAX get request.' не появился!"

Почему именно text_to_be_present_in_element? После клика элемент .bg-success появляется в DOM, но текст в нём может появиться чуть позже. Это условие ждёт именно нужного текста, а не просто присутствия элемента.

Пример 3. Авторизация в OrangeHRM

Сайт: opensource-demo.orangehrmlive.com
Проверяем успешный вход с корректными учётными данными двумя способами: по заголовку и по URL.

Решение 1 — проверка через заголовок h6

# test_orangehrm_login.py
import pytest
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service


@pytest.fixture
def driver():
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)
    driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
    yield driver
    driver.quit()


def test_login_to_orangehrm(driver):
    wait = WebDriverWait(driver, 10)  # Явное ожидание до 10 секунд

    # Вводим имя пользователя
    username_field = driver.find_element(By.NAME, "username")
    username_field.send_keys("Admin")

    # Вводим пароль
    password_field = driver.find_element(By.NAME, "password")
    password_field.send_keys("admin123")

    # Нажимаем кнопку Login
    login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
    login_button.click()

    # Ожидаем появления заголовка "Dashboard"
    dashboard_header = wait.until(
        EC.text_to_be_present_in_element((By.TAG_NAME, "h6"), "Dashboard")
    )

    # Проверяем, что заголовок содержит "Dashboard"
    assert dashboard_header, "Текст заголовка не содержит 'Dashboard'"

Решение 2 — проверка через URL

# test_orangehrm_login_url.py (дополнение к фикстуре выше)

def test_login_and_check_url(driver):
    wait = WebDriverWait(driver, 10)

    # Вводим учётные данные
    driver.find_element(By.NAME, "username").send_keys("Admin")
    driver.find_element(By.NAME, "password").send_keys("admin123")
    driver.find_element(By.XPATH, "//button[@type='submit']").click()

    # Ожидаем, пока URL изменится и будет содержать "dashboard"
    wait.until(EC.url_contains("dashboard"))

    # Проверяем, что в URL содержится "dashboard"
    assert "dashboard" in driver.current_url, \
        f"Ожидаемый URL не содержит 'dashboard': {driver.current_url}"

Пример 4. Slow Calculator — WebDriverWait с большим таймаутом

Сайт: bonigarcia.dev/selenium-webdriver-java/slow-calculator.html
Калькулятор выдаёт результат с задержкой. Нужно подождать до 50 секунд.

# test_slow_calculator.py
import pytest
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service


@pytest.fixture
def driver():
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)
    driver.get("https://bonigarcia.dev/selenium-webdriver-java/slow-calculator.html")
    yield driver
    driver.quit()


def test_slow_calculator(driver):
    wait = WebDriverWait(driver, 50)  # Ожидание до 50 секунд (задержка 45 сек)

    # Вводим задержку 45 секунд в поле #delay
    delay_input = driver.find_element(By.CSS_SELECTOR, "#delay")
    delay_input.clear()
    delay_input.send_keys("45")

    # Нажимаем кнопки: 7, +, 8, =
    driver.find_element(By.XPATH, "//span[text()='7']").click()
    driver.find_element(By.XPATH, "//span[text()='+']").click()
    driver.find_element(By.XPATH, "//span[text()='8']").click()
    driver.find_element(By.XPATH, "//span[text()='=']").click()

    # Ждём появления результата "15" через 45 секунд
    result_element = wait.until(
        EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".screen"), "15")
    )

    # Проверяем, что результат действительно 15
    assert result_element, "Ожидаемый результат '15' не отобразился!"

Пример 5. Проверка валидации формы

Сайт: bonigarcia.dev/selenium-webdriver-java/data-types.html
Заполняем форму, оставляем Zip code пустым, проверяем классы валидации.

# test_form_validation.py
import pytest
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service


@pytest.fixture
def driver():
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)
    driver.get("https://bonigarcia.dev/selenium-webdriver-java/data-types.html")
    yield driver
    driver.quit()


def test_form_validation(driver):
    wait = WebDriverWait(driver, 10)

    # Заполняем форму
    driver.find_element(By.NAME, "first-name").send_keys("Hans")
    driver.find_element(By.NAME, "last-name").send_keys("Schmidt")
    driver.find_element(By.NAME, "address").send_keys("Berliner Straße, 55-3")
    driver.find_element(By.NAME, "email").send_keys("test@itch.de")
    driver.find_element(By.NAME, "phone").send_keys("+4917623456789")
    # Zip code оставляем пустым (намеренная ошибка)
    driver.find_element(By.NAME, "zip-code").clear()
    driver.find_element(By.NAME, "city").send_keys("Berlin")
    driver.find_element(By.NAME, "country").send_keys("Deutschland")
    driver.find_element(By.NAME, "job-position").send_keys("QA")
    driver.find_element(By.NAME, "company").send_keys("ITCH")

    # Нажимаем Submit
    driver.find_element(By.XPATH, "//button[@type='submit']").click()

    # Ожидаем, пока поле Zip code станет невалидным (класс is-invalid)
    wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='zip-code'].is-invalid"))
    )
    zip_field = driver.find_element(By.NAME, "zip-code")
    assert "is-invalid" in zip_field.get_attribute("class"), \
        "Поле Zip code не подсвечено красным!"

    # Проверяем, что остальные поля зелёные (класс is-valid)
    valid_fields = ["first-name", "last-name", "address", "email",
                    "phone", "city", "country", "job-position", "company"]
    for field_name in valid_fields:
        wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, f"input[name='{field_name}'].is-valid"))
        )
        field = driver.find_element(By.NAME, field_name)
        assert "is-valid" in field.get_attribute("class"), \
            f"Поле {field_name} не подсвечено зелёным!"

Обратите внимание: мы ждём появления в DOM элемента с классом .is-invalid через presence_of_element_located с CSS-селектором, который включает класс. Это надёжнее, чем просто найти поле и потом проверить класс без ожидания.