Playwright Python — справочник На главный сайт

Структура теста с pytest

Playwright предоставляет плагин для pytest, который автоматически управляет браузером, контекстом и страницей. Вам не нужно вручную создавать и закрывать браузер — всё делается через фикстуры. Базовый тест выглядит так:

def test_page_title(page):
    page.goto("https://example.com")
    assert page.title() == "Example Domain"

В этом примере page — это фикстура, предоставленная плагином pytest-playwright. Она автоматически создаёт новый браузерный контекст и страницу для каждого теста, а после завершения теста закрывает их.

Как это работает: Плагин pytest-playwright регистрирует несколько фикстур — browser, context и page. Они создаются заново для каждого теста, что обеспечивает полную изоляцию. Если тест завершается неудачей, браузер всё равно будет закрыт.

Фикстуры pytest-playwright

Плагин предоставляет три основные фикстуры:

Фикстура browser

Запускает экземпляр браузера. По умолчанию используется Chromium в headless-режиме. Фикстура живёт на протяжении всего теста и автоматически закрывается после его завершения.

def test_with_browser(browser):
    page = browser.new_page()
    page.goto("https://example.com")

Фикстура context

Создаёт новый браузерный контекст — изолированную сессию с собственными куками, localStorage и кэшем. Контекст используется для симуляции разных пользователей или разных устройств.

def test_with_context(context):
    page = context.new_page()
    page.goto("https://example.com")

Фикстура page

Самая часто используемая фикстура. Она создаёт новый контекст и одну страницу в нём. Именно эту фикстуру вы будете использовать в большинстве тестов.

def test_title(page):
    page.goto("https://example.com")
    assert page.title() == "Example Domain"

Совет: Все три фикстуры автоматически управляют временем жизни объектов. Вам не нужно вызывать browser.close() или page.close() — pytest сделает это за вас. Это предотвращает утечки ресурсов в тестах.

Правила именования тестов

pytest обнаруживает тесты по следующим правилам:

  • Файлы должны называться test_*.py или *_test.py
  • Функции должны начинаться с test_
  • Классы с тестами должны начинаться с Test и не иметь метода __init__
# test_example.py
def test_checkbox(page):
    page.goto("https://example.com")
    page.locator("#checkbox").check()
    assert page.locator("#checkbox").is_checked()

Паттерн AAA (Arrange, Act, Assert)

Рекомендуется структурировать тесты по паттерну AAA:

  • Arrange (Подготовка) — настройка начального состояния: переход на страницу, заполнение форм, установка данных
  • Act (Действие) — выполнение тестируемого действия: клик, отправка формы, ввод текста
  • Assert (Проверка) — проверка ожидаемого результата: текст на странице, видимость элемента, URL
def test_search(page):
    # Arrange
    page.goto("https://example.com/search")

    # Act
    page.locator("#search-input").fill("Playwright")
    page.locator("#search-button").click()

    # Assert
    results = page.locator(".result-item")
    assert results.count() > 0
    expect(results.first).to_contain_text("Playwright")

Полный пример теста

Ниже приведён полноценный тест для формы входа:

def test_login(page):
    page.goto("https://example.com/login")

    # Заполнение полей
    page.locator("#username").fill("testuser")
    page.locator("#password").fill("testpass123")

    # Отправка формы
    page.locator("button[type='submit']").click()

    # Проверка успешного входа
    expect(page).to_have_url("https://example.com/dashboard")
    expect(page.locator(".welcome-message")).to_be_visible()
    expect(page.locator(".welcome-message")).to_contain_text("Добро пожаловать")

Асинхронные тесты

Playwright поддерживает как синхронный, так и асинхронный API. Для асинхронных тестов используйте фикстуру async_page и определяйте тестовые функции через async def:

import pytest


async def test_async_title(async_page):
    await async_page.goto("https://example.com")
    title = await async_page.title()
    assert title == "Example Domain"

Важно: Для асинхронных тестов убедитесь, что у вас установлен pytest-asyncio. Добавьте его в зависимости проекта: pip install pytest-asyncio. Затем настройте pytest для использования asyncio-режима в pyproject.toml.

Использование Playwright как библиотеки (без pytest)

Если вы не используете pytest, вы можете работать с Playwright через контекстный менеджер sync_playwright(). Этот подход часто используется в скриптах для веб-скрапинга или в интеграционных тестах с другими фреймворками:

from playwright.sync_api import sync_playwright


def run():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context(
            viewport={"width": 1280, "height": 720}
        )
        page = context.new_page()
        page.goto("https://example.com")
        print(page.title())
        browser.close()


if __name__ == "__main__":
    run()

Контекстный менеджер гарантирует, что все ресурсы (процессы браузера, сокеты) будут корректно освобождены после завершения работы.

Распространённые действия в тестах

Playwright поддерживает все основные действия пользователя:

  • Навигация: page.goto(url) — переход по URL
  • Клик: page.locator(selector).click() — клик по элементу
  • Ввод текста: page.locator(selector).fill(text) — заполнение поля
  • Чекбоксы: page.locator(selector).check() / .uncheck()
  • Селекты: page.locator(selector).select_option(value)
  • Скриншоты: page.screenshot(path="screenshot.png")
  • Ожидание: page.wait_for_selector(selector) — ожидание появления элемента
def test_user_flow(page):
    page.goto("https://example.com/signup")

    # Заполнение формы регистрации
    page.locator("#name").fill("Иван Петров")
    page.locator("#email").fill("ivan@example.com")
    page.locator("#country").select_option("RU")
    page.locator("#agree-terms").check()

    # Отправка
    page.locator("button[type='submit']").click()

    # Проверка успешной регистрации
    expect(page.locator(".success-message")).to_be_visible()

Группировка тестов в классах

Для организации связанных тестов можно использовать классы:

class TestUserProfile:

    def test_view_profile(self, page):
        page.goto("https://example.com/profile")
        expect(page.locator(".user-name")).to_have_text("Иван Петров")

    def test_edit_profile(self, page):
        page.goto("https://example.com/profile/edit")
        page.locator("#bio").fill("QA Engineer")
        page.locator("#save").click()
        expect(page.locator(".toast")).to_contain_text("Сохранено")

Совет: Используйте фикстуру page как аргумент метода класса — pytest автоматически прокидывает её. Вы также можете определить фикстуры уровня класса с помощью @pytest.fixture(scope="class") для переиспользования контекста.

Лучшие практики

  • Избегайте time.sleep(): Playwright имеет встроенное Auto-Waiting. Используйте expect() вместо произвольных задержек.
  • Используйте семантические локаторы: Предпочитайте get_by_role() и get_by_test_id() вместо CSS-селекторов.
  • Один тест — одна проверка: Каждый тест должен проверять одно поведение. Это упрощает отладку.
  • Не смешивайте синхронный и асинхронный API: Выберите один стиль и придерживайтесь его во всём проекте.
  • Используйте фикстуру page: Она автоматически управляет ресурсами. Не создавайте браузер вручную в тестах.

Переходите к разделу Запуск тестов, чтобы узнать, как запускать, конфигурировать и получать отчёты о выполнении тестов.