Как выглядит структура сложного end-to-end (E2E) автотеста с использованием Selenium и Pytest?

«Как выглядит структура сложного end-to-end (E2E) автотеста с использованием Selenium и Pytest?» — вопрос из категории Автоматизация тестирования, который задают на 10% собеседований QA Тестировщик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Сложный E2E-тест моделирует ключевой пользовательский сценарий, например, оформление заказа. Важны стабильность, читаемость и правильные ожидания.

Пример: Тест оформления заказа в интернет-магазине

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(scope="function")
def browser():
    """Фикстура для инициализации и закрытия браузера."""
    driver = webdriver.Chrome()
    driver.implicitly_wait(5)  # Неявное ожидание (резерв)
    driver.maximize_window()
    yield driver
    driver.quit()

def test_complete_purchase_flow(browser):
    """E2E-тест: авторизация, добавление товара, оформление заказа."""
    wait = WebDriverWait(browser, 15)  # Явные ожидания для ключевых действий

    # 1. АВТОРИЗАЦИЯ
    browser.get("https://demo-shop.example.com/login")
    browser.find_element(By.ID, "email").send_keys("test.user@example.com")
    browser.find_element(By.ID, "password").send_keys("SecurePass123")
    browser.find_element(By.XPATH, "//button[text()='Sign In']").click()

    # Ожидание успешного входа (редирект или появление элемента)
    wait.until(EC.url_contains("/dashboard"))

    # 2. ВЫБОР И ДОБАВЛЕНИЕ ТОВАРА
    browser.find_element(By.LINK_TEXT, "Catalog").click()
    product_card = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, ".product-card:first-child"))
    )
    product_card.find_element(By.CLASS_NAME, "add-to-cart-btn").click()

    # Ожидание появления уведомления или обновления счетчика корзины
    notification = wait.until(
        EC.visibility_of_element_located((By.CLASS_NAME, "cart-notification"))
    )
    assert "added to cart" in notification.text.lower()

    # 3. ПЕРЕХОД В КОРЗИНУ И ПРОВЕРКА
    browser.find_element(By.CLASS_NAME, "cart-icon").click()
    cart_page_title = wait.until(
        EC.visibility_of_element_located((By.TAG_NAME, "h1"))
    )
    assert "Your Cart" in cart_page_title.text

    # Проверка наличия товара и его цены в корзине
    item_price = browser.find_element(By.CSS_SELECTOR, ".cart-item-price").text
    assert "$" in item_price

    # 4. ПРОЦЕСС ОФОРМЛЕНИЯ ЗАКАЗА
    browser.find_element(By.ID, "checkout-button").click()
    wait.until(EC.url_contains("/checkout"))

    # Заполнение данных доставки (можно вынести в отдельный метод)
    browser.find_element(By.NAME, "address").send_keys("123 Main St")
    # ... заполнение других полей

    browser.find_element(By.ID, "place-order-btn").click()

    # 5. ВЕРИФИКАЦИЯ УСПЕШНОГО ЗАКАЗА
    confirmation_message = wait.until(
        EC.visibility_of_element_located((By.CLASS_NAME, "order-confirmation"))
    )
    assert "Thank you for your order" in confirmation_message.text
    assert "order number" in browser.page_source.lower()

Ключевые практики в примере:

  1. Явные ожидания (WebDriverWait): Ожидание конкретных условий вместо time.sleep(), что повышает стабильность.
  2. Четкие локаторы: Приоритет: By.ID > By.CSS_SELECTOR > By.XPATH.
  3. Логическая структура: Комментариями разделены этапы сценария.
  4. Утверждения (Assert): Проверки на каждом логическом этапе, а не только в конце.
  5. Фикстура Pytest: Управляет жизненным циклом браузера, код чистый.