Написание тестов
Структура тестов Playwright, использование фикстур pytest, базовые паттерны и примеры кода.
Структура теста с 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: Она автоматически управляет ресурсами. Не создавайте браузер вручную в тестах.
Переходите к разделу Запуск тестов, чтобы узнать, как запускать, конфигурировать и получать отчёты о выполнении тестов.