Тестовые раннеры
Запуск тестов Playwright с pytest, unittest и BDD-подходами. Встроенные и кастомные фикстуры, параллельный запуск, маркеры, шардирование и отчёты.
pytest-playwright — основной раннер
Playwright предоставляет официальную интеграцию с pytest через пакет pytest-playwright. Это самый удобный и рекомендуемый способ запуска тестов. Он предоставляет встроенные фикстуры, автоматическую настройку браузеров и богатые возможности конфигурации.
# Установка
pip install pytest-playwright
playwright install
Встроенные фикстуры: page, context, browser, playwright — доступны сразу после установки. Каждая фикстура создаётся заново для каждого теста, если не указано иное.
Базовый пример с pytest-playwright
# test_example.py def test_login(page): page.goto("https://example.com/login") page.get_by_label("Email").fill("user@example.com") page.get_by_label("Пароль").fill("secret123") page.get_by_role("button", name="Войти").click() expect(page.get_by_text("Добро пожаловать")).to_be_visible()
Фикстуры pytest-playwright
page — изолированная страница
Каждый тест получает новую page (и новый контекст, и новый браузер). Это обеспечивает полную изоляцию.
context — браузерный контекст
Позволяет работать с контекстом напрямую, например, для тестирования нескольких вкладок.
def test_multi_tab(context): page1 = context.new_page() page2 = context.new_page() page1.goto("https://example.com") page2.goto("https://playwright.dev")
browser — браузерный процесс
Даёт доступ к запущенному браузеру. Полезно для создания контекстов с кастомными настройками.
def test_custom_context(browser): context = browser.new_context( viewport={"width": 1920, "height": 1080}, locale="ru-RU" ) page = context.new_page() page.goto("https://example.com")
playwright — корневой объект
Предоставляет доступ к Playwright API для запуска браузеров вручную.
def test_with_playwright(playwright): chromium = playwright.chromium browser = chromium.launch(headless=True)
Кастомные фикстуры
Вы можете создавать собственные фикстуры для переиспользования логики между тестами.
# conftest.py import pytest from playwright.sync_api import Page @pytest.fixture def auth_page(page: Page) -> Page: page.goto("https://example.com/login") page.get_by_label("Email").fill("admin@example.com") page.get_by_label("Пароль").fill("admin123") page.get_by_role("button", name="Войти").click() return page # test_dashboard.py def test_dashboard(auth_page): auth_page.goto("https://example.com/dashboard") expect(auth_page.get_by_text("Панель управления")).to_be_visible()
Совет: Используйте scope="session" для фикстур, которые должны создаваться один раз на всю сессию тестирования, например, для авторизованного контекста.
@pytest.fixture(scope="session") def auth_context(browser): context = browser.new_context(storage_state="auth.json") yield context context.close() def test_with_auth(auth_context): page = auth_context.new_page() page.goto("https://example.com/profile")
conftest.py — глобальные фикстуры и хуки
Файл conftest.py автоматически загружается pytest и позволяет определять глобальные фикстуры, хуки и переопределения. Размещайте его в корне тестовой директории.
# conftest.py — расширенный пример import pytest from playwright.sync_api import sync_playwright @pytest.fixture(scope="session") def browser_context_args(browser_context_args): return { "viewport": {"width": 1920, "height": 1080}, "locale": "ru-RU", "timezone_id": "Europe/Moscow", } def pytest_runtest_makereport(item, call): """Хук: скриншот при падении теста""" if call.when == "call" and call.excinfo is not None: page = item.funcargs.get("page") if page: page.screenshot(path="failure.png")
pytest.ini / pyproject.toml — конфигурация
Настройки pytest-playwright можно задать в pytest.ini или pyproject.toml.
pytest.ini
# pytest.ini
[pytest]
testpaths = tests
addopts = -v --headed --slowmo=100
filterwarnings =
ignore::DeprecationWarning
pyproject.toml
# pyproject.toml [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-v --headed --slowmo=100"
Основные CLI-флаги pytest-playwright:
| Флаг | Описание |
|---|---|
--headed | Запуск с видимым браузером |
--browser=chromium | Выбор браузера (chromium/firefox/webkit) |
--browser=all | Запуск во всех браузерах |
--slowmo=100 | Задержка между действиями в мс |
--device="iPhone 13" | Эмуляция устройства |
--video=on | Запись видео |
--screenshot=only-on-failure | Скриншоты только при падении |
--tracing=on | Трассировка |
Параллельный запуск: pytest-xdist
Для ускорения тестов используйте плагин pytest-xdist. Playwright поддерживает параллельный запуск на уровне браузера.
# Установка pip install pytest-xdist # Запуск с 4 процессами pytest -n auto # Указать количество воркеров явно pytest -n 4
Важно: При параллельном запуске каждый воркер использует отдельный браузер. Убедитесь, что тесты изолированы и не зависят от общего состояния.
Переиспользование браузера: --reuse
Флаг --reuse позволяет переиспользовать один экземпляр браузера между тестами, что ускоряет запуск при параллельном выполнении.
pytest --reuse --workers 4
При такой конфигурации один браузерный процесс обслуживает несколько воркеров, что снижает накладные расходы на запуск и закрытие браузера для каждого теста.
Маркеры: skip_browser и only_browser
Playwright предоставляет маркеры для управления браузерами, в которых запускаются тесты.
import pytest @pytest.mark.skip_browser("firefox") def test_chromium_only(page): "Тест будет пропущен в Firefox" page.goto("https://example.com") @pytest.mark.only_browser("chromium") def test_only_chromium(page): "Запускается только в Chromium" page.goto("https://example.com")
Маркеры работают только при запуске с --browser=all. Иначе Playwright запускает браузер по умолчанию (chromium) без учёта маркеров.
Sharding — распределение тестов в CI
Sharding позволяет разделить тесты на несколько групп (шардов) для параллельного выполнения на разных CI-агентах.
# CI-задача 1: запускает первую четверть тестов pytest --shard=1/4 # CI-задача 2: запускает вторую четверть pytest --shard=2/4 # CI-задача 3: третья четверть pytest --shard=3/4 # CI-задача 4: четвёртая четверть pytest --shard=4/4
Sharding особенно полезен при ограниченном времени выполнения CI-пайплайна. Каждый шард выполняется на отдельном агенте, и общее время сокращается пропорционально количеству шардов.
pytest --max-failures — остановка при первом падении
Флаг --max-failures останавливает тестовый прогон после указанного количества упавших тестов.
pytest --max-failures=1
Это удобно для быстрой обратной связи: если один тест упал, нет смысла запускать остальные — ошибка уже есть и нужно её исправить.
HTML-отчёты: pytest-html
Плагин pytest-html генерирует детальный HTML-отчёт о результатах тестирования.
# Установка pip install pytest-html # Запуск с генерацией отчёта pytest --html=report.html --self-contained-html
Флаг --self-contained-html встраивает все ресурсы (CSS, изображения) прямо в HTML-файл, что удобно для хранения артефактов CI.
Allure-отчёты
Allure Framework предоставляет богатые интерактивные отчёты с историей прогонов, графиками и вложениями.
# Установка pip install allure-pytest # Запуск с сохранением результатов Allure pytest --alluredir=./allure-results # Генерация и открытие отчёта allure serve ./allure-results
Совет: Allure поддерживает аннотации для обогащения отчётов: @allure.title, @allure.description, @allure.feature, @allure.story и @allure.step.
import allure @allure.feature("Авторизация") @allure.story("Успешный вход") def test_login_success(page): with allure.step("Открыть страницу логина"): page.goto("https://example.com/login") with allure.step("Заполнить учётные данные"): page.get_by_label("Email").fill("user@example.com") page.get_by_label("Пароль").fill("secret123") with allure.step("Нажать кнопку входа"): page.get_by_role("button", name="Войти").click() with allure.step("Проверить успешный вход"): expect(page.get_by_text("Добро пожаловать")).to_be_visible()
BDD: pytest-bdd с Playwright
Playwright отлично интегрируется с pytest-bdd для Behavior-Driven Development. Вы пишете сценарии на Gherkin, а шаги реализуете с использованием Playwright.
# login.feature
Feature: Авторизация
Scenario: Успешный вход
Given пользователь открыл страницу логина
When пользователь вводит email "user@example.com"
And пользователь вводит пароль "secret123"
And пользователь нажимает "Войти"
Then пользователь видит приветствие
# test_login.py from pytest_bdd import scenarios, given, when, then scenarios("login.feature") @given("пользователь открыл страницу логина") def open_login(page): page.goto("https://example.com/login") @when('пользователь вводит email "<email>"') def enter_email(page, email): page.get_by_label("Email").fill(email) @when('пользователь вводит пароль "<password>"') def enter_password(page, password): page.get_by_label("Пароль").fill(password) @when('пользователь нажимает "Войти"') def click_login(page): page.get_by_role("button", name="Войти").click() @then("пользователь видит приветствие") def see_welcome(page): expect(page.get_by_text("Добро пожаловать")).to_be_visible()
unittest — Playwright как библиотека
Playwright можно использовать с классическим unittest без pytest. В этом случае вы управляете жизненным циклом браузера вручную.
import unittest from playwright.sync_api import sync_playwright class TestLogin(unittest.TestCase): def setUp(self): self.playwright = sync_playwright().start() self.browser = self.playwright.chromium.launch() self.context = self.browser.new_context() self.page = self.context.new_page() def tearDown(self): self.browser.close() self.playwright.stop() def test_login_page(self): self.page.goto("https://example.com/login") self.page.get_by_label("Email").fill("user@example.com") self.page.get_by_role("button", name="Войти").click() self.assert_true( self.page.get_by_text("Добро пожаловать").is_visible() ) if __name__ == "__main__": unittest.main()
Недостаток unittest: Вам нужно вручную управлять браузером, контекстом и страницами. Также отсутствуют встроенные фикстуры, автоматический скриншот при падении и другие удобства pytest-playwright.
Заключение
pytest-playwright — самый мощный и удобный способ запуска тестов. Используйте встроенные фикстуры для изоляции тестов, кастомные фикстуры для переиспользования логики, параллельный запуск через xdist для ускорения, а BDD-подход для улучшения читаемости сценариев. Для CI-пайплайнов применяйте шардирование, HTML- или Allure-отчёты.