Автоматизация тестирования с Playwright (Python) и Pytest: Frontend + Backend, архитектура Page Object

Курс для тех, кто уже знает основы Python, Pytest/Selenium и ручное тестирование и хочет перейти на современную автоматизацию на Playwright. Сначала выстроим надежную архитектуру UI-автотестов (Page Object, Page Factory, Page Components), затем добавим backend/API-тестирование и интеграцию в CI.

1. Введение: Playwright vs Selenium, установка, структура проекта, первый тест на Pytest

Введение: Playwright vs Selenium, установка, структура проекта, первый тест на Pytest

Зачем этот курс и что мы будем автоматизировать

Этот курс про построение поддерживаемой автоматизации тестирования на Python, где:

  • для UI (Frontend) мы используем Playwright
  • для запуска и организации тестов используем Pytest
  • для архитектуры проекта применяем Page Object, а также подходы Page Components и Page Factory
  • во второй части добавим тестирование Backend (API) и связку UI + API в одном проекте
  • У вас уже есть база: Python, Pytest, Selenium и понимание ручного тестирования. Значит, мы сфокусируемся не на синтаксисе, а на том, как быстро и стабильно писать тесты, которые не разваливаются от каждого изменения UI.

    Playwright vs Selenium

    Selenium и Playwright решают похожую задачу: управлять браузером и взаимодействовать со страницей. Но у Playwright есть несколько важных отличий, из-за которых он часто удобнее именно для современной веб-автоматизации.

    Ключевые отличия

    | Критерий | Selenium | Playwright | |---|---|---| | Ожидания (waits) | Часто нужно явно писать ожидания (implicit/explicit waits) | Встроенные авто-ожидания для большинства действий (клик, ввод, проверка видимости) | | Работа с селекторами | CSS/XPath, часто много ручной логики | Поддержка CSS/XPath, а также “локаторы” (locators) и удобные стратегии поиска | | Параллельность и скорость | Возможна, но обычно требует больше усилий | Часто проще масштабировать, быстрее стартует, удобно в CI | | Мультибраузерность | Требует драйверов (ChromeDriver, GeckoDriver и т.д.) | Браузеры устанавливаются одной командой playwright install | | Network/HTTP | Обычно отдельные библиотеки | Есть встроенный API-клиент (полезно для Backend-части) | | Изоляция тестов | Нужно аккуратно управлять профилями/куками | Контексты браузера (browser contexts) дают удобную изоляцию |

    Официальные источники:

  • Документация Playwright: Playwright Python
  • Документация Selenium: Selenium Documentation
  • Что такое авто-ожидания в Playwright

    Когда вы пишете действие вроде “кликнуть по кнопке”, Playwright перед кликом пытается убедиться, что элемент:

  • существует в DOM
  • видим
  • доступен для взаимодействия
  • Это снижает количество флейковых (нестабильных) тестов и уменьшает потребность в ручных sleep и “сложных” ожиданиях. При этом важно понимать: авто-ожидания не отменяют необходимость думать о стабильных селекторах и корректной архитектуре.

    Установка: Python, Pytest, Playwright

    Ниже базовый путь установки для проекта на Pytest с Playwright.

    Подготовка окружения

  • Создайте папку проекта и виртуальное окружение.
  • Активируйте окружение.
  • Установите зависимости.
  • Пример команд:

    Установка Playwright и интеграции с Pytest

    Есть два распространённых способа:

  • использовать “чистый” Playwright и самим управлять запуском браузера
  • использовать плагин pytest-playwright, который даёт готовые фикстуры browser, context, page
  • Для курса на старте удобнее второй вариант.

    Установка:

    Теперь важно установить сами браузеры (Chromium/Firefox/WebKit), которыми управляет Playwright:

    Документация плагина:

  • pytest-playwright
  • Документация Pytest:

  • Pytest Documentation
  • Минимальная структура проекта

    Мы сразу будем строить проект так, чтобы он рос без боли: тесты отдельно, Page Object отдельно, конфиги отдельно.

    !Схема рекомендуемой структуры проекта и связей между слоями

    Один из удобных вариантов структуры:

    Коротко по смыслу папок и файлов:

  • tests/ — сами тесты (то, что мы запускаем)
  • pages/Page Object: классы страниц, где лежат локаторы и методы действий
  • components/Page Components: переиспользуемые части UI (хедер, меню, модалки)
  • api/ — клиент для запросов к backend и API-тестов (вторая часть курса)
  • utils/ — вспомогательные вещи: конфиги, генераторы данных, обёртки
  • conftest.py — фикстуры Pytest (например, авторизация, базовые настройки)
  • pytest.ini — настройки Pytest (марки, дефолтные опции)
  • requirements.txt — зависимости проекта
  • Термины архитектуры, которые мы будем использовать

  • Page Object — класс, который представляет страницу (или крупный экран) и предоставляет методы “действий пользователя” (например, login(username, password)). Внутри — локаторы и низкоуровневые операции.
  • Page Components — класс, который представляет часть страницы, переиспользуемую на разных страницах (например, хедер, сайдбар, виджет корзины).
  • Page Factory — подход, когда создание страниц/компонентов централизовано (например, через “фабрику”), чтобы управлять зависимостями единообразно. Мы будем применять этот подход позже, когда появится больше страниц и общих зависимостей.
  • Первый тест на Pytest + Playwright

    Ниже — минимальный рабочий пример, который открывает страницу и проверяет заголовок.

    Файл теста

    Создайте файл tests/ui/test_example.py:

    Что здесь происходит:

  • page — это фикстура, которую предоставляет pytest-playwright
  • page.goto(...) — переход по URL
  • page.title() — получение заголовка вкладки
  • assert ... — стандартная проверка Pytest
  • Запуск теста

    Из корня проекта:

    Если всё установлено корректно, Pytest:

  • создаст браузер
  • создаст контекст (изолированную среду)
  • создаст страницу
  • выполнит тест
  • Полезные опции запуска

    Для начальной отладки часто нужно видеть браузер.

  • Запуск в “видимом” режиме:
  • Запуск с замедлением действий (удобно при разборе проблем вживую):
  • Опции зависят от раннера Playwright, который используется через плагин.

    Минимальная настройка Pytest

    Создайте pytest.ini в корне проекта, чтобы хранить базовые настройки.

    Пример:

    Смысл:

  • addopts = -ra — показывает дополнительную информацию по упавшим/пропущенным тестам
  • testpaths = tests — где Pytest ищет тесты по умолчанию
  • Типичные ошибки на старте и как их быстро диагностировать

  • Ошибка: тесты не стартуют, Playwright ругается на отсутствие браузеров.
  • - Решение: выполните playwright install.

  • Ошибка: Pytest не видит фикстуру page.
  • - Решение: проверьте, что установлен pytest-playwright, и что вы запускаете тесты в том же виртуальном окружении.

  • Ошибка: тест “иногда падает”.
  • - Решение: временно запустите pytest --headed --slowmo 300 и посмотрите, что происходит в UI. Затем — улучшайте селекторы и структуру ожиданий.

    Итог

    В этой статье вы:

  • поняли, чем Playwright отличается от Selenium и почему он часто даёт более стабильные UI-тесты
  • установили pytest, pytest-playwright и браузеры Playwright
  • заложили базовую структуру проекта под масштабирование и архитектуру Page Object
  • написали и запустили первый тест на Pytest
  • Дальше мы начнём строить “правильный” каркас: фикстуры, базовые страницы, локаторы, правила работы с ожиданиями и подготовку к Page Components и Page Factory.

    2. Основы UI в Playwright: локаторы, ожидания, навигация, окна, фреймы, загрузки

    Основы UI в Playwright: локаторы, ожидания, навигация, окна, фреймы, загрузки

    Контекст курса и цель темы

    В прошлой статье вы установили Playwright и pytest-playwright, настроили базовую структуру проекта и запустили первый тест с фикстурой page.

    Дальше нам нужно научиться писать стабильные UI-тесты. Практически вся стабильность в Playwright упирается в:

  • локаторы (как мы находим элементы)
  • ожидания (как мы синхронизируемся с UI)
  • корректную работу с навигацией, новыми окнами, фреймами и загрузками файлов
  • После этой статьи вы сможете уверенно писать шаги UI-теста и понимать, почему Playwright ведёт себя стабильно без sleep.

    Официальная документация Playwright для Python, на которую будем опираться:

  • Locators
  • Assertions (expect)
  • Pages
  • Frames
  • Downloads
  • Локаторы в Playwright

    Что такое Locator и почему это важно

    В Playwright вы обычно работаете не с элементом, а с Locator. Locator — это объект, который:

  • хранит стратегию поиска элемента
  • может переиспользоваться
  • автоматически ждёт, когда элемент станет готов к действию
  • Это одна из ключевых причин, почему Playwright часто менее флейковый, чем Selenium.

    Два подхода: page.locator() и get_by_*

    Playwright поддерживает разные способы описать, что именно вы ищете.

    | Подход | Пример | Когда использовать | |---|---|---| | page.locator() | page.locator("css=button.save") | когда нужно точно и гибко управлять селектором | | get_by_* локаторы | page.get_by_role("button", name="Save") | когда вы хотите устойчивые селекторы, похожие на то, как видит страницу пользователь |

    На практике для поддерживаемости лучше начинать с get_by_role, get_by_label, get_by_text, get_by_test_id, а locator() оставлять для случаев, где семантических зацепок нет.

    Рекомендованная стратегия селекторов

    Самый практичный порядок (от более устойчивого к менее устойчивому):

  • get_by_role() с name=
  • get_by_label() для полей ввода
  • get_by_test_id() если в проекте есть договорённость про data-testid
  • get_by_text() аккуратно, когда текст стабилен
  • locator("css=...")
  • XPath как крайний случай
  • #### Примеры get_by_role

    Почему это хорошо:

  • роль и имя обычно меняются реже, чем классы в CSS
  • такой поиск ближе к доступности (a11y) и реальному поведению пользователя
  • #### Пример get_by_label для инпутов

    get_by_test_id и договорённость в команде

    Если есть возможность влиять на продукт, одна из лучших практик для автотестов — добавить атрибуты вида data-testid.

    Важный момент: Playwright по умолчанию ожидает data-testid, но это поведение можно настраивать. На старте курса достаточно придерживаться дефолта.

    Уточнение локатора: filter, nth, цепочки

    Когда элементов много, локатор можно уточнить.

    Практический смысл:

  • cards описывает набор элементов
  • nth(1) берёт второй (индексация с нуля)
  • дальше мы работаем внутри выбранной карточки
  • Что считается плохим локатором

  • локатор завязан на динамические классы (.sc-123abc) или DOM-структуру, которая часто меняется
  • локатор использует длинный CSS-путь через много уровней
  • локатор завязан на текст, который постоянно редактируют
  • Ожидания в Playwright

    Авто-ожидания: что Playwright делает за вас

    Большинство действий (например, click(), fill()) Playwright выполняет с авто-ожиданиями. Обычно это значит, что перед действием он дождётся, что элемент:

  • существует
  • видим
  • доступен для взаимодействия
  • Но важно понимать границу ответственности: авто-ожидания помогают для действий, а вот для проверок состояния страницы лучше использовать expect.

    expect как основной способ проверок

    В Playwright проверка через expect обычно стабильнее, чем assert, потому что expect умеет ждать разумное время.

    Идея: мы не делаем ручных ожиданий. Мы формулируем ожидаемое состояние, а Playwright ждёт.

    Когда нужны явные ожидания

    Явные ожидания полезны, когда вы ждёте не элемент напрямую, а событие или состояние страницы:

  • смена URL
  • завершение навигации
  • открытие нового окна
  • старт загрузки файла
  • появление фрейма
  • #### Примеры ожиданий

    | Сценарий | Пример | |---|---| | ждать конкретный URL | page.wait_for_url("**/dashboard") | | ждать конкретное состояние загрузки | page.wait_for_load_state("domcontentloaded") | | ждать элемент в нужном состоянии | locator.wait_for(state="visible") |

    Почему не стоит использовать time.sleep

    time.sleep:

  • замедляет тесты всегда, даже когда приложение работает быстро
  • не решает проблему синхронизации надёжно, если приложение иногда работает медленнее
  • Playwright-ожидания привязаны к реальным событиям и состояниям, поэтому обычно стабильнее.

    Навигация: переходы, редиректы и загрузка страницы

    page.goto() и базовые правила

    page.goto(url) открывает страницу и ждёт загрузки по умолчанию.

    assert здесь допустим, потому что page.title() возвращает значение сразу. Но для UI-состояний (элементы, тексты) предпочтительнее expect.

    Действия, которые вызывают навигацию

    Частая ошибка — сделать клик, который открывает другую страницу, и сразу начать искать элементы новой страницы.

    В Playwright правильнее синхронизироваться через ожидание URL или состояния.

    wait_for_load_state и почему networkidle нужно применять осторожно

    Есть несколько состояний загрузки:

  • domcontentloaded — DOM построен
  • load — ресурсы страницы в основном загружены
  • networkidle — сеть была относительно спокойна некоторое время
  • На современных SPA networkidle иногда может никогда не наступить из-за фоновых запросов аналитики, вебсокетов и подобного. Поэтому чаще используют:

  • wait_for_url + ожидание ключевого элемента через expect
  • Новые окна и вкладки (popups)

    Типовой сценарий

    Пользователь кликает по ссылке, которая открывается в новой вкладке. В Playwright это отдельный объект Page.

    Надёжный способ — ждать событие popup через контекстный менеджер.

    Практический смысл:

  • мы сначала говорим Playwright: сейчас ожидаем popup
  • затем выполняем действие
  • получаем ссылку на новую вкладку и работаем уже с ней
  • Когда нужно использовать context.expect_page()

    Если новое окно открывается не как popup с текущей страницы, а в результате действий на уровне контекста (редко, но бывает), можно использовать ожидание новой страницы на context.

    В рамках курса чаще достаточно page.expect_popup().

    Фреймы (iframes)

    Почему фреймы требуют особого подхода

    Если элемент находится внутри iframe, обычный page.get_by_* его не найдёт, потому что это другой документ.

    В Playwright для этого есть frame_locator().

    frame_locator как основной инструмент

    Рекомендация: старайтесь держать работу с фреймом внутри соответствующего Page Object или Component, чтобы тесты не разрастались в сложные конструкции.

    Как понять, что элемент внутри iframe

    Типичные признаки:

  • вы видите элемент в браузере, но Playwright сообщает, что элемент не найден
  • в DevTools вы находите нужный элемент только после переключения в iframe
  • Загрузки файлов (downloads)

    Ожидание загрузки через expect_download

    Когда клик запускает скачивание файла, важно поймать событие загрузки.

    Что важно:

  • expect_download синхронизирует тест с фактом начала загрузки
  • suggested_filename удобен для сохранения с ожидаемым именем
  • tmp_path — стандартная фикстура Pytest для временных файлов
  • Проверка содержимого файла

    В UI-части курса обычно достаточно проверить, что файл скачался и не пустой. Проверки формата и содержимого можно добавить позже как отдельный уровень (например, для CSV или PDF).

    Мини-паттерны для устойчивых UI-тестов

    Паттерн: действие + проверка результата

    Вместо того чтобы делать много действий подряд, лучше фиксировать промежуточные состояния.

    Пример структуры шага:

  • выполнить действие (click, fill, select_option)
  • проверить результат через expect (видимость, текст, URL)
  • Паттерн: минимум логики в тесте

    Тест должен отвечать на вопрос что проверяем. А как именно кликаем и заполняем — это зона Page Object и Components, к которым мы скоро перейдём.

    !Схема показывает, где должны жить локаторы и действия, чтобы тесты были поддерживаемыми

    Итог

    Вы изучили базовые механики UI в Playwright, без которых невозможно построить стабильную автоматизацию:

  • как выбирать локаторы и почему get_by_* часто лучше
  • как работают авто-ожидания и почему expect предпочтительнее для UI-проверок
  • как синхронизироваться с навигацией без sleep
  • как обрабатывать новые окна, фреймы и загрузки файлов
  • В следующих материалах мы начнём систематизировать эти знания в архитектуру: вынесем локаторы и действия в Page Object, выделим Components и подготовим основу для Page Factory.

    3. Pytest для UI: фикстуры browser/page, конфиги, параметризация, маркеры, parallel

    Pytest для UI: фикстуры browser/page, конфиги, параметризация, маркеры, parallel

    Зачем нам отдельная тема про Pytest в UI-автотестах

    В предыдущих статьях вы:

  • установили Playwright и pytest-playwright
  • написали первый UI-тест
  • разобрали локаторы и ожидания, которые делают тесты стабильнее
  • Теперь нужно превратить набор отдельных тестов в управляемый тестовый проект. Это почти всегда делается средствами Pytest:

  • фикстуры создают и настраивают окружение тестов (браузер, контекст, страница, авторизация)
  • конфиги фиксируют правила запуска (где лежат тесты, какие маркеры есть, какие опции включать по умолчанию)
  • параметризация позволяет проверять одно и то же поведение на разных данных и конфигурациях
  • маркеры помогают запускать подмножества тестов
  • параллельный запуск ускоряет прогон и приближает проект к CI
  • Основные источники:

  • Документация Pytest
  • Документация Playwright Python
  • Pytest plugin для Playwright (pytest-playwright)
  • pytest-xdist (параллельный запуск)
  • Фикстуры pytest-playwright: browser, context, page

    Что такое фикстура в Pytest

    Фикстура — это функция, которая:

  • подготавливает тестовые данные или окружение
  • отдаёт их тесту
  • при необходимости делает корректный teardown
  • В UI-тестах фикстуры особенно важны, потому что запуск браузера, создание контекста и страницы должны быть единообразными.

    Какие фикстуры даёт pytest-playwright

    Плагин pytest-playwright предоставляет готовые фикстуры, из которых чаще всего используются:

  • browser — запущенный браузер (например, Chromium)
  • contextbrowser context, изолированная среда (куки, localStorage, разрешения)
  • page — вкладка/страница в рамках контекста
  • Идея такая: один browser может содержать много context, а каждый context может содержать много page.

    !Как связаны browser, context и page и почему это важно для изоляции

    Почему context важнее, чем кажется

    В Selenium часто пытаются "чистить" куки между тестами. В Playwright правильно мыслить так:

  • каждый тест получает новый context
  • значит тесты меньше зависят друг от друга
  • меньше флейка из-за состояния, оставшегося после предыдущего сценария
  • Минимальный пример теста, который использует page

    Обратите внимание: expect здесь полезнее, чем assert, потому что он умеет ждать ожидаемое состояние.

    Свои фикстуры в conftest.py: базовый URL, навигация, авторизация

    Зачем нужен conftest.py

    conftest.py — файл, который Pytest автоматически подхватывает как источник фикстур и хуков.

    Практическая цель: тесты должны быть короткими и читатьcя как сценарии, а не как набор технических настроек.

    Фикстура для базового URL

    Создадим единый источник правды для URL. Это пригодится и для UI, и позже для API.

    utils/config.py:

    conftest.py:

    Тест:

    Фикстура, которая открывает страницу перед тестом

    Если большинство тестов начинается с открытия одной и той же страницы, можно вынести это в фикстуру.

    Использование:

    Авторизация через storage_state

    Для реальных проектов типичный путь ускорения UI-тестов:

  • один раз логинимся
  • сохраняем состояние контекста (куки, localStorage)
  • дальше создаём контекст уже с этим состоянием
  • В Playwright это называется storage state. Общая идея описана в документации Playwright про браузерные контексты и состояние, а в проектах с pytest-playwright обычно делают так:

  • отдельной командой или фикстурой создают файл состояния, например artifacts/auth.json
  • в фикстуре контекста используют этот файл
  • Важно: точная реализация зависит от вашего приложения и способа логина. В рамках курса мы закрепим подход, а конкретную реализацию сделаем, когда появится своя тестовая система логина.

    Конфигурация Pytest: pytest.ini и консистентные запуски

    Зачем нужен pytest.ini

    pytest.ini помогает:

  • фиксировать базовые опции запуска
  • объявлять маркеры (чтобы Pytest не ругался)
  • задать папки с тестами
  • Пример pytest.ini для UI-части курса:

    Пояснения:

  • addopts = -ra показывает дополнительную информацию по итогам прогона
  • testpaths = tests задаёт корневую папку тестов
  • markers объявляет маркеры, чтобы их можно было безопасно использовать
  • Полезные опции командной строки для UI

    На старте отладки обычно нужны:

  • --headed чтобы видеть браузер
  • --slowmo 300 чтобы замедлить действия
  • Пример:

    Для запуска в разных браузерах pytest-playwright поддерживает опцию --browser.

    Пример:

    А также можно прогонять сразу в нескольких браузерах, повторяя опцию.

    Пример:

    Точное поведение и доступные опции зависят от версии pytest-playwright, поэтому в команде важно договориться о фиксированной версии в requirements.txt.

    Параметризация: проверяем больше сценариев без копипаста

    Базовая parametrize для данных

    Классика Pytest — @pytest.mark.parametrize. Это способ одним тестом проверить несколько наборов данных.

    Здесь:

  • path и title — параметры теста
  • список кортежей — тестовые наборы
  • ids делает отчёт читаемым
  • Параметризация сценариев через объекты

    Часто удобнее параметризовать не примитивами, а структурой.

    Польза: тест остаётся читаемым, даже когда данных много.

    Параметризация на уровне фикстур

    Иногда нужно менять окружение, а не только входные данные. В Pytest это делается через параметризацию фикстуры.

    Пример идеи:

  • вы хотите запускать один и тот же тест
  • но с разными настройками контекста (например, язык интерфейса)
  • Это можно сделать параметризованной фикстурой context или вспомогательной фикстурой, которая отдаёт параметры. Конкретные поля настроек зависят от продукта, поэтому в курсе мы закрепим этот паттерн на реальном приложении.

    Маркеры: управляем тем, что запускаем

    Зачем нужны маркеры

    Когда тестов становится много, появляется потребность запускать разные наборы:

  • smoke перед релизом
  • regression ночью
  • только ui тесты
  • Как ставить маркеры

    Как запускать по маркерам

  • Запустить только smoke:
  • Запустить UI, но не regression:
  • skip и xfail в UI-тестах

    Иногда тест нельзя выполнять:

  • фича отключена
  • есть известный баг
  • окружение временно нестабильно
  • Тогда полезны:

  • @pytest.mark.skip(reason="...")
  • @pytest.mark.xfail(reason="...", strict=True)
  • xfail стоит использовать осторожно: если вы ожидаете падение, легко пропустить момент, когда проблема уже исправлена. Включение strict=True помогает, потому что внезапный успех становится сигналом.

    Параллельный запуск: ускоряем UI-тесты с pytest-xdist

    Зачем parallel

    UI-тесты дорогие по времени. Параллелизация даёт практически линейный выигрыш, если:

  • тесты изолированы
  • нет конкуренции за общие данные
  • Установка и запуск

    Установка:

    Запуск на всех доступных ядрах:

    Что может сломаться при параллельном запуске

    Параллельность выявляет архитектурные проблемы. Типовые причины падений:

  • тесты используют одного и того же пользователя и конфликтуют по состоянию
  • тесты создают данные с одинаковыми именами
  • тесты используют общую папку для файлов
  • Практические правила:

  • используйте tmp_path для файлов, чтобы у каждого теста был свой каталог
  • делайте тестовые данные уникальными (например, добавляйте суффикс)
  • избегайте зависимостей между тестами
  • Как связаны parallel и Playwright contexts

    В Playwright изоляция обычно строится через context, но параллельность добавляет ещё один слой:

  • разные воркеры xdist — это разные процессы Pytest
  • в каждом процессе создаются свои браузеры/контексты
  • Итого: если вы правильно используете context и не шарите состояние через глобальные переменные или общую БД без уникализации данных, параллельный запуск становится намного проще.

    Итог

    В этой статье вы собрали фундамент Pytest для UI-автоматизации на Playwright:

  • поняли роль фикстур browser, context, page и почему context — ключ к изоляции
  • научились выносить повторяющуюся подготовку в conftest.py
  • настроили pytest.ini для консистентного запуска и маркеров
  • освоили параметризацию как способ расширять покрытие без копипаста
  • разобрали маркеры для управления наборами тестов
  • поняли, как подключать и безопасно использовать parallel через pytest-xdist
  • Следующий шаг курса логично продолжает эту тему: мы начнём выносить UI-логику из тестов в архитектуру Page Object, добавим Page Components и подготовим основу для Page Factory, чтобы проект масштабировался без хаоса.

    4. Page Object Model: дизайн страниц, читаемые шаги, стабильные проверки и тестовые данные

    Page Object Model: дизайн страниц, читаемые шаги, стабильные проверки и тестовые данные

    Контекст: зачем нам Page Object именно сейчас

    В предыдущих темах вы научились уверенно писать UI-шаги на Playwright и организовывать запуск через Pytest: фикстуры page/context, маркеры, параметризация, parallel.

    Следующая проблема, которая возникает почти сразу после первых 10–20 UI-тестов:

  • тесты начинают дублировать одни и те же локаторы и шаги
  • изменения UI приводят к массовым правкам по всему проекту
  • появляются случайные ожидания, sleep и нестабильность
  • Page Object Model (POM) решает это за счёт разделения ответственности: тест описывает что проверяем, а Page Object описывает как взаимодействуем со страницей.

    Официальные материалы, которые полезно держать под рукой:

  • Page object models
  • Playwright Python: Locators
  • Playwright Python: Assertions (expect)
  • Pytest: Fixtures
  • !Схема разделения ответственности между тестами, страницами, компонентами и тестовыми данными

    Что такое Page Object Model и какие задачи он решает

    Page Object это класс, который представляет страницу (или крупный экран) и предоставляет методы, соответствующие действиям пользователя.

    POM обычно даёт четыре практических эффекта:

  • Поддерживаемость: локаторы и UI-детали спрятаны в одном месте.
  • Читаемость: тесты превращаются в понятные сценарии.
  • Стабильность: ожидания и проверки состояния стандартизируются.
  • Переиспользование: общие шаги (логин, поиск, навигация) не копируются.
  • Главный принцип POM

  • В тестах не должно быть CSS/XPath и низкоуровневых операций.
  • В Page Object не должно быть бизнес-логики продукта, которая не относится к UI.
  • Границы ответственности: тесты, страницы, компоненты

    Чтобы POM не превратился в новый хаос, полезно зафиксировать правила.

    Что должно быть в тесте

  • бизнес-смысл сценария
  • выбор входных данных
  • финальные проверки поведения (часто через методы страниц)
  • Что должно быть в Page Object

  • локаторы страницы
  • действия (ввод, клик, выбор)
  • методы ожиданий и проверок состояния страницы
  • методы, которые возвращают следующую страницу после навигации
  • Что должно быть в Page Component

    Component это часть интерфейса, встречающаяся на разных страницах.

    Примеры:

  • хедер
  • сайдбар
  • модалка
  • карточка товара
  • Компонент обычно принимает page и корневой Locator, чтобы работать внутри своей области.

    Дизайн Page Object: базовые правила, которые экономят недели

    Правило: методы страницы описывают действия пользователя

    Плохо:

  • click_login_button()
  • type_into_email_field()
  • Хорошо:

  • login_as(email, password)
  • submit_login()
  • search(product_name)
  • То есть метод называется по смыслу шага, а не по UI-детали.

    Правило: локаторы не должны утекать в тест

    Плохо:

    Хорошо:

    Правило: ожидания живут рядом с действием

    Если клик вызывает навигацию, ожидание URL должно быть внутри метода страницы.

    Плохо:

    Хорошо:

    Каркас: BasePage как единый стандарт для всех страниц

    Обычно у всех страниц есть общие потребности:

  • хранить page
  • открываться по относительному пути
  • иметь методы базовых ожиданий
  • Пример минимального BasePage.

    Зачем path:

  • у каждой страницы есть понятный URL-адрес
  • открытие стандартизировано
  • тесты не клеят URL руками
  • Пример Page Object: LoginPage

    Ниже пример страницы логина, где:

  • локаторы спрятаны внутри
  • действия оформлены методами
  • проверки оформлены методами
  • Почему локаторы сделаны через @property:

  • тест и внешний код не модифицируют их напрямую
  • читается как “элемент страницы”, а не “как искать элемент”
  • Альтернатива: хранить селекторы строками и создавать локатор в методе. Такой стиль тоже допустим, но в Playwright чаще удобнее хранить именно Locator.

    Должны ли проверки быть внутри Page Object

    В проектах встречаются две крайности:

  • Page Object содержит только действия, а все expect живут в тестах.
  • Page Object содержит и действия, и проверки, и иногда даже сценарии целиком.
  • Практичный баланс для курса:

  • Page Object содержит короткие методы-проверки состояния, например should_show_error(), should_be_opened(), should_have_user_avatar().
  • Тест использует эти методы как читаемые утверждения.
  • Так тест остаётся декларативным, а ожидания стандартизированы.

    Навигация между страницами: методы возвращают следующую страницу

    Если после сабмита логина открывается дашборд, удобно чтобы метод возвращал объект новой страницы.

    И дополним LoginPage:

    Плюсы:

  • тест не думает про wait_for_url
  • “переход” оформлен как понятный шаг
  • Page Components: переиспользуемые части интерфейса

    Компоненты помогают, когда один и тот же UI повторяется на разных страницах.

    Пример: хедер, который отображает имя пользователя и содержит кнопку Logout.

    Как подключать компонент на странице:

    Теперь тест может делать так:

    Page Factory: единая точка создания страниц

    Когда страниц становится много, в тестах появляется повторение:

  • везде надо передавать page
  • везде нужен base_url
  • Page Factory это простой слой, который стандартизирует создание объектов.

    Фикстура для фабрики:

    Тест начинает читаться как сценарий:

    Тестовые данные: как сделать данные удобными и не сломать стабильность

    POM решает проблему UI-слоя, но тесты всё равно зависят от данных. Если данные неорганизованы, проект становится нестабильным по другой причине.

    Правило: отделяем тестовые данные от UI-шагов

    Удобный минимальный подход: описывать данные через dataclass.

    Теперь методы страниц принимают не россыпь строк, а объект:

    Data Factory: фабрики данных для тестов

    Часто нужно создавать разные варианты данных.

    Плюсы:

  • все тестовые учётки в одном месте
  • сценарии читаются проще
  • Про генерацию случайных данных

    Генерация (например, email с рандомным суффиксом) полезна, когда тест создаёт сущности и должен избегать конфликтов, особенно при parallel.

    Если вы используете Faker, это реальный и популярный инструмент:

  • Faker documentation
  • Практическое правило стабильности:

  • случайные данные используйте там, где это необходимо
  • добавляйте “контроль” (например, логируйте сгенерированное значение или делайте воспроизводимый seed на уровне теста), чтобы падения можно было расследовать
  • Как выглядит итоговый тест: читаемые шаги и стабильные проверки

    Негативный сценарий логина с параметризацией и Page Object:

    Что важно:

  • тест не знает о локаторах
  • тест не содержит явных ожиданий
  • ожидание “ошибка видима и содержит текст” оформлено стандартно
  • Типовые ошибки при внедрении POM

    Ошибка: Page Object превращается в “свалку”

    Признаки:

  • в одном классе 50+ методов
  • методы делают сразу много разных вещей
  • Лечение:

  • выделяйте компоненты
  • делайте методы короткими: одно действие или одна проверка
  • Ошибка: тесты начинают вызывать page.locator() напрямую

    Это ломает главный смысл POM. Если очень нужно получить доступ к локатору, лучше:

  • добавить метод get_* или свойство на странице
  • или добавить метод-проверку, чтобы тест не работал с локатором напрямую
  • Ошибка: ожидания размазаны между тестом и страницей

    Если часть ожиданий в тесте, часть в Page Object, поддерживать сложно. Договоритесь о стиле:

  • ожидания навигации и UI-состояний после действий держите в Page Object
  • тест оставляйте декларативным
  • Итог

    В этой теме вы заложили основу архитектуры UI-части проекта:

  • поняли, как Page Object Model разделяет ответственность и повышает поддерживаемость
  • научились проектировать Page Object с локаторами, действиями и методами-проверками
  • разобрали Page Components для переиспользуемых частей UI
  • увидели, как Page Factory упрощает создание страниц и уменьшает бойлерплейт
  • научились отделять тестовые данные от UI и оформлять их фабриками/датаклассами
  • Дальше эта архитектура станет фундаментом для более сложных вещей: авторизация через storage_state, масштабирование набора страниц, а во второй части курса мы добавим API-слой и связку UI+API в одной модели проекта.

    5. Page Factory и Page Components: композиция, переиспользование, виджеты, таблицы, модалки

    Page Factory и Page Components: композиция, переиспользование, виджеты, таблицы, модалки

    Зачем выделять Components и усиливать Factory

    В прошлой теме вы построили базовую архитектуру Page Object Model: тесты стали короче, локаторы переехали в классы страниц, а навигация начала возвращать следующий Page Object.

    Дальше почти в каждом реальном UI-проекте возникает новая боль:

  • один и тот же фрагмент интерфейса повторяется на многих страницах
  • внутри страницы появляются сложные блоки: таблицы, фильтры, модалки, тосты, выпадающие списки
  • Page Object разрастается и превращается в “монолит”, который сложно поддерживать
  • Эту проблему решает композиция:

  • Page Components выделяют повторяемые и сложные части страницы
  • Page Factory становится единым способом создавать страницы и компоненты, уменьшая бойлерплейт и стандартизируя зависимости
  • Официальные источники, на которые опираемся:

  • Playwright: Page Object Models
  • Playwright Python: Locators
  • Playwright Python: Assertions
  • Pytest: Fixtures
  • !Общая картина композиции: тесты → фабрика → страницы → компоненты

    Page Components как способ держать страницы маленькими

    Что такое компонент

    Page Component это класс, который инкапсулирует часть UI:

  • может переиспользоваться на разных страницах
  • имеет собственные локаторы и методы действий
  • обычно ограничен корневым локатором root, чтобы работать только “внутри себя”
  • Ключевой принцип: компонент не должен искать элементы по всей странице без необходимости. Если компонент начинается с page.get_by_* по всей странице, он быстро станет источником конфликтов локаторов.

    Минимальный базовый класс компонента

    В Playwright удобно хранить в компоненте два поля:

  • page для событий уровня страницы (например, ожидание download, popup, диалог)
  • root для всех локаторов внутри компонента
  • Этот класс сам по себе ничего не делает, но задаёт единый контракт.

    Компонент “Хедер” как пример переиспользования

    Хедер часто одинаков на десятках страниц: имя пользователя, кнопка выхода, иногда поиск.

    Подключение хедера на странице:

    Теперь любой тест или страница может использовать dashboard.header.logout() без копипаста локаторов.

    Компоненты-виджеты

    Под виджетом здесь будем понимать “самодостаточный UI-блок” со своим состоянием и логикой.

    Типовые виджеты:

  • фильтр с полями и кнопкой Apply
  • тосты уведомлений (success/error)
  • выпадающий список (dropdown)
  • date picker
  • Компонент Toast (уведомления)

    Тосты часто флейкают, если проверять их через assert без ожиданий. Правильнее оформить компонент, который сам ждёт появления.

    Подключение на странице:

    Практический эффект: ожидания стандартизированы, и тесты перестают “случайно” падать из-за задержек анимаций.

    Модалки как компонент

    Почему модалки лучше оформлять отдельным классом

    Модалка обычно имеет повторяемые паттерны:

  • состояние открыта/закрыта
  • кнопки Confirm/Cancel
  • заголовок
  • иногда поля ввода и ошибки
  • Если оставить модалку в Page Object, страница быстро раздувается.

    Пример ConfirmModal

    Подключение на странице:

    Важная договорённость: корень модалки должен быть устойчиво доступен, чаще всего через data-testid.

    Таблицы как компонент: строки, действия, поиск нужной записи

    Таблицы в тестах часто становятся источником хрупких локаторов, потому что:

  • DOM-структура может быть сложной
  • внутри строки есть кнопки действий
  • нужно находить строку по значению в колонке
  • Идея: оформить таблицу как компонент, а строку таблицы как подкомпонент.

    TableRow как “подкомпонент”

    Table как компонент

    Пример, где строки имеют data-testid="users-row", а внутри есть ячейки user-email, user-role.

    Подключение на странице:

    Использование в тесте выглядит так, будто вы работаете с бизнес-сущностями, а не с HTML:

    Здесь тест не знает, что такое tr, td, классы и CSS.

    Композиция: как правильно “собирать” страницу из компонентов

    Практичные правила композиции:

  • Страница хранит точки входа в компоненты через @property.
  • Компонент ищет элементы через root, а не “по всей странице”.
  • Сложный компонент можно разделять на подкомпоненты: таблица → строка → ячейка.
  • Проверки состояния, которые зависят от UI-тайминга, лучше держать внутри компонента через expect.
  • !Как страница состоит из компонентов и как root ограничивает область поиска

    Page Factory как единая точка создания страниц и компонентов

    Зачем Page Factory, если можно просто писать LoginPage(page, base_url)

    Когда проект маленький, можно создавать страницы напрямую. Когда проект растёт, появляются типовые проблемы:

  • в каждом тесте повторяются page и base_url
  • часть страниц требует дополнительные зависимости (в будущих темах это будет API-клиент)
  • хочется единообразия: один стиль создания, одна точка для расширения
  • Простой вариант фабрики

    Фикстура Pytest:

    Тесты становятся консистентными по стилю.

    Когда фабрике полезно кэширование

    Если у вас много обращений к одной и той же странице в рамках одного теста, можно кэшировать экземпляры страниц внутри фабрики.

    Правило: кэширование допустимо, если объект страницы не хранит “временное состояние”, завязанное на конкретный шаг. Большинство Page Object хранит только page и base_url, значит кэш обычно безопасен.

    Пример аккуратного кэширования без магии:

    Если вы не уверены, нужно ли кэширование, не добавляйте его. Создание Page Object дёшево.

    Границы ответственности: частые ошибки и рабочие правила

    Ошибка: компонент начинает жить “сам по себе” и делает навигацию

    Компонент не должен открывать страницы и управлять маршрутизацией приложения. Навигация это ответственность Page Object.

    Правило:

  • Page Object знает путь и переходы
  • Component знает только свою область root
  • Ошибка: тест лезет внутрь компонента локаторами

    Плохо:

    Хорошо:

    Ошибка: компоненты завязаны на нестабильные CSS-классы

    Стабильнее строить локаторы через:

  • get_by_role и доступные имена
  • get_by_label для полей
  • get_by_test_id при договорённости в продукте
  • Подходы к локаторам и авто-ожиданиям были разобраны в теме про основы UI.

    Итог

    Теперь ваша UI-архитектура стала масштабируемой:

  • Page Components позволяют переиспользовать хедеры, тосты, фильтры, модалки и таблицы
  • Композиция через root делает локаторы устойчивее и уменьшает конфликты
  • Table + Row компоненты превращают работу с таблицами в читаемый API
  • Page Factory стандартизирует создание страниц и готовит проект к расширению зависимостей (в том числе для backend-части курса)
  • Дальше логичный следующий шаг в рамках UI-части: закрепить единый подход к общим зависимостям (авторизация через storage_state, конфиги окружений, подготовка тестовых данных), а затем перейти ко второй части курса: тестированию API и связке UI + API в одном проекте.

    6. Backend часть: API-тесты на Pytest (requests или Playwright APIRequestContext), схемы, контракты

    Backend часть: API-тесты на Pytest (requests или Playwright APIRequestContext), схемы, контракты

    Как API-часть ложится на уже построенную UI-архитектуру

    В UI-части курса мы построили каркас, в котором:

  • тесты остаются короткими и читаемыми
  • Page Object и Components прячут локаторы, ожидания и технические детали
  • Page Factory стандартизирует создание страниц и зависимостей
  • Во второй части мы добавляем Backend слой: API-тесты на Pytest. Цель та же, что и в UI:

  • поддерживаемость через единый клиент и модели данных
  • стабильность через понятные проверки и схемы
  • масштабирование через фикстуры и разделение ответственности
  • Ключевая идея связки UI и API в одном проекте:

  • API поможет готовить тестовые данные для UI (создать пользователя, заказ, настройки)
  • UI поможет проверить критичные пользовательские сценарии поверх уже проверенного API
  • один проект, один запуск Pytest, единая структура отчётности и артефактов
  • !Схема, показывающая место API-клиента рядом с Page Object и то, как строятся UI, API и UI+API тесты

    Что такое API-тесты и какие задачи они закрывают

    API-тесты проверяют поведение системы на уровне HTTP-интерфейса.

    Чаще всего мы проверяем:

  • статус-коды и обработку ошибок
  • структуру ответа и обязательные поля
  • типы данных и бизнес-правила на уровне контракта
  • авторизацию и права доступа
  • идемпотентность и корректность повторных запросов
  • API-тесты обычно:

  • быстрее UI
  • стабильнее UI
  • проще для диагностики, потому что видны запрос и ответ
  • Но они не заменяют UI-тесты, потому что не проверяют реальное отображение и пользовательский путь в браузере.

    Чем писать API-тесты: requests или Playwright APIRequestContext

    В Python есть два практичных подхода для API-тестов в рамках нашего курса.

    Вариант A: requests

    Библиотека Requests это стандарт де-факто для HTTP в Python.

    Плюсы:

  • максимально распространена
  • удобна для чистых API-проектов
  • легко использовать requests.Session() для общих заголовков и cookie
  • Минусы в контексте нашего курса:

  • это отдельный стек рядом с Playwright, нужно отдельно решать некоторые вопросы интеграции
  • Вариант B: Playwright APIRequestContext

    Playwright умеет работать с HTTP напрямую через APIRequestContext.

    Документация:

  • Playwright Python API testing
  • Плюсы:

  • один стек инструментов для UI и API
  • проще делать интеграционные тесты UI+API в одном прогоне
  • удобно управлять авторизацией и базовым URL через контекст
  • Минусы:

  • меньше привычен тем, кто долго работал только с requests
  • Что выбрать в курсе

    Мы будем держать архитектуру так, чтобы вы могли использовать оба подхода. Практический совет:

  • если у вас уже есть опыт и готовые наработки на requests, не нужно ломать себя
  • если проект уже на Playwright и вы хотите единообразия, берите APIRequestContext
  • Главное не библиотека, а архитектура:

  • единый API-клиент
  • модели и схемы
  • фикстуры Pytest
  • Структура проекта: куда класть API-слой

    Мы продолжаем использовать структуру, которая уже появлялась в UI-части, и добавляем детали для API.

    Пример:

    Роли файлов:

  • api/client.py это единая точка HTTP-вызовов
  • api/models.py это модели и схемы ответов
  • api/endpoints.py это константы путей, чтобы не размазывать строки по проекту
  • Конфигурация: base_url для UI и base_api_url для API

    У реальных систем часто разные адреса:

  • base_url для фронтенда
  • base_api_url для backend API
  • Расширим utils/config.py (идея, не единственный вариант):

    Важно:

  • секреты вроде API_TOKEN не храним в репозитории
  • в CI токены и адреса задаются переменными окружения
  • Базовый API-клиент: единый стиль запросов и ошибок

    Типичная ошибка в начале API-автоматизации это писать запросы прямо в тестах. Это быстро превращается в копипаст:

  • дублируются заголовки
  • размазывается логика авторизации
  • ошибки проверяются по-разному
  • Нам нужен слой, аналогичный Page Object, только для API.

    Клиент на requests

    Клиент на Playwright APIRequestContext

    Ключевая разница:

  • requests обычно работает с абсолютными URL, которые вы склеиваете сами
  • Playwright-контекст удобно создавать с base_url, и тогда в клиенте достаточно относительных путей
  • Pytest фикстуры для API: клиент, контекст, авторизация

    Фикстура для requests-клиента

    conftest.py:

    Фикстура для Playwright APIRequestContext

    Если вы используете pytest-playwright, у вас доступна фикстура playwright.

    conftest.py:

    И фикстура клиента поверх контекста:

    Практическая причина делать именно так:

  • тесты получают готовый клиент
  • создание и уничтожение контекста стандартизировано
  • в будущем сюда легко добавить логирование, таймауты, базовые проверки
  • Как писать API-тесты: структура и понятные проверки

    Базовый пример: статус-код и ключевое поле

    Это минимально, но быстро становится недостаточно, потому что:

  • непонятно, какие поля обязательны
  • не проверяются типы и формат
  • при изменении контракта тесты либо молча перестают что-то замечать, либо массово падают без ясной причины
  • Дальше нам нужны схемы и контракт.

    Схемы ответов: зачем они нужны и как их проверять

    Схема ответа это описание структуры данных:

  • какие поля должны присутствовать
  • какие типы у значений
  • какие поля могут быть null
  • какие значения допустимы
  • Схемы решают две проблемы:

  • тест становится менее хрупким к добавлению новых полей
  • тест становится более строгим к поломке обязательных полей и типов
  • Подход 1: Pydantic модели

    Pydantic позволяет описывать ожидаемую структуру как Python-класс.

    Пример модели в api/models.py:

    Тест:

    Что здесь происходит:

  • model_validate проверяет, что JSON соответствует модели
  • если поле отсутствует или тип несовместим, вы получите понятную ошибку в месте проверки
  • Плюс этого подхода:

  • модели можно переиспользовать между тестами
  • удобно работать с данными как с объектом
  • Подход 2: JSON Schema

    Если в компании уже есть схемы в формате JSON Schema, их удобно валидировать напрямую.

    Библиотека: jsonschema

    Пример схемы в api/schemas/user.json (упрощённо):

    Тест:

    Когда выбирать какой подход:

  • Pydantic удобнее, когда вы хотите типизированные модели в коде
  • JSON Schema удобнее, когда схемы приходят извне как артефакт контракта
  • Контракт API: что мы на самом деле фиксируем тестами

    Контракт API это договорённость между клиентами и сервером.

    Минимальный контракт для endpoint обычно включает:

  • метод и путь, например GET /users/{id}
  • правила авторизации, например нужен Bearer token
  • статус-коды для разных сценариев
  • структуру успешного ответа
  • структуру ошибки
  • Важный практический момент:

  • контрактные тесты должны быть строгими к обязательным вещам
  • но не должны быть слишком строгими к деталям, которые не важны клиентам
  • Пример: если API добавило новое поле middle_name, тесты по схеме должны проходить, если поле не обязательное.

    !Диаграмма, показывающая роль контракта как источника истины между бэкендом, автотестами и клиентами

    OpenAPI как контракт и как с ним работать в тестах

    Во многих проектах контракт описан в OpenAPI спецификации.

    Документация формата:

  • OpenAPI Specification
  • Варианты использования в тестах:

  • Хранить ссылку на спецификацию и проверять ключевые endpoints вручную через модели и схемы.
  • Подключать генеративное тестирование по спецификации, например через Schemathesis, чтобы автоматически проверять соответствие контракту.
  • В рамках курса базовым будет подход номер 1, потому что он лучше объясняет архитектуру, а подход номер 2 станет логичным развитием, когда вы закрепите фундамент.

    Негативные сценарии: ошибки тоже часть контракта

    Частая ошибка начинающих это тестировать только успешные ответы.

    Негативные сценарии должны фиксировать:

  • корректный статус-код, например 401 или 403
  • структуру ошибки, например { "error": { "code": "...", "message": "..." } }
  • отсутствие утечек внутренних деталей, если это важно для безопасности
  • Пример:

    Примечание: в реальном проекте вы не будете хардкодить URL в тесте, это показано только как короткий пример идеи. В нашем каркасе это делается через settings и фикстуры.

    Полезные практики для стабильных API-тестов

  • Держите HTTP-вызовы в api/client.py, а не в тестах.
  • Выделяйте модели и схемы в api/models.py или api/schemas/.
  • Проверяйте не только happy path, но и ошибки как часть контракта.
  • В параллельном запуске избегайте конфликтов данных.
  • Фиксируйте, какие поля обязательны, а какие нет.
  • Если API-тесты начинают падать хаотично, чаще всего причина не в HTTP, а в том, что тесты делят состояние:

  • один и тот же пользователь
  • одни и те же сущности
  • общие данные в базе без уникализации
  • Эти проблемы мы будем решать в интеграционных темах UI+API через фабрики тестовых данных.

    Итог

    Вы добавили в проект backend-направление и заложили правильный фундамент:

  • поняли, когда использовать requests, а когда Playwright APIRequestContext
  • научились выносить HTTP-вызовы в единый API-клиент и подключать его через фикстуры Pytest
  • разобрали, как проверять ответы не только по значениям, но и по схемам
  • поняли, что такое контракт API и почему он должен быть отражён в тестах
  • увидели, как OpenAPI может выступать источником истины для контрактных проверок
  • Следующий логичный шаг курса после этой темы это интеграция UI+API в одной архитектуре: подготовка данных через API, ускорение UI сценариев, единые фабрики данных и единый Page Factory, который умеет выдавать и страницы, и API-клиенты.

    7. Сборка качества: репорты, трассировки/видео, Allure, тестовые окружения и CI/CD пайплайн

    Сборка качества: репорты, трассировки/видео, Allure, тестовые окружения и CI/CD пайплайн

    Зачем нужна сборка качества в проекте автотестов

    В прошлых темах вы построили архитектуру тестов:

  • UI на Playwright + Pytest с Page Object, Components и Page Factory
  • API-тесты на Pytest с единым API-клиентом, моделями и контрактными проверками
  • Но в реальном проекте важен не только код тестов, а воспроизводимый процесс, который отвечает на вопросы:

  • что именно запускали (какие тесты, какие версии, какие окружения)
  • где упало и почему (репорты, логи, скриншоты, трассировки)
  • как быстро чинить (артефакты для диагностики)
  • как стабильно прогонять в CI на разных ветках
  • Под сборкой качества будем понимать связку:

  • стандартизированные отчёты и артефакты
  • диагностика UI-падений через trace, видео и скриншоты
  • Allure как единый читаемый отчёт по UI и API
  • управление тестовыми окружениями
  • CI/CD пайплайн, который каждый раз запускается одинаково
  • !Общая схема того, как тесты запускаются и превращаются в отчёты и артефакты

    Базовые артефакты, которые должны быть в проекте

    Артефакты помогают диагностировать падения без повторного запуска на своей машине.

    Рекомендуемый набор:

  • лог запуска Pytest
  • traces Playwright для UI-падений
  • видео для UI-падений
  • скриншоты на падениях
  • Allure results как единый формат “сырья” для отчётов
  • Полезное правило: артефакты собираем всегда, но “тяжёлые” артефакты делаем хотя бы по падениям, чтобы не раздувать хранение.

    Репорты Pytest: что использовать как минимум

    Встроенный отчёт Pytest в консоли

    Минимальная база уже есть в pytest.ini:

    Это даёт понятный список упавших тестов и причины.

    Дополнительно в CI полезно включать:

  • --maxfail=1 для быстрого фидбека в smoke
  • -q для компактного вывода
  • -m smoke или -m "ui and not regression" для селекции набора
  • JUnit XML для CI-систем

    Многие CI умеют отображать тест-результаты из JUnit XML.

    Команда:

    Плюсы:

  • понятная интеграция с CI
  • базовая аналитика по тестам
  • Минусы:

  • плохо подходит для диагностики UI без дополнительных артефактов
  • Документация:

  • Pytest: JUnit XML format
  • Tracing, видео и скриншоты Playwright: диагностика UI-падений

    Что такое trace и почему он важнее видео

    Trace в Playwright это запись технических событий теста:

  • действия (клики, fill)
  • ожидания
  • сетевые запросы
  • DOM-снимки и снапшоты
  • Trace открывается в Trace Viewer, где можно пошагово понять, что именно видел Playwright.

    Документация:

  • Playwright: Trace Viewer
  • Вариант через pytest-playwright: опции командной строки

    Если вы используете pytest-playwright, многие вещи можно включить флагами.

    Пример запуска, который собирает артефакты только по падениям:

    Смысл режимов:

  • retain-on-failure сохраняет артефакт только если тест упал
  • only-on-failure аналогично, но для скриншотов
  • Документация по pytest-интеграции:

  • Playwright: Pytest runner
  • Вариант через свои фикстуры: контроль над путями и именами

    Иногда нужно жёстко управлять тем, куда и как сохраняются traces, особенно в CI.

    Пример идеи: стартуем tracing в фикстуре context, а на падении теста сохраняем файл.

    conftest.py:

    Как использовать:

  • тесты получают traced_page вместо page
  • Плюсы:

  • полный контроль над именем и каталогом
  • Минусы:

  • больше кода поддержки
  • Практическая рекомендация для курса: начать с флагов pytest-playwright, а кастомный контроль добавлять, когда появятся требования CI.

    Allure: единый отчёт для UI и API

    Зачем Allure, если есть JUnit XML

    Allure ценен тем, что объединяет:

  • структуру тестов по suites
  • вложенные шаги
  • вложения: скриншоты, логи, traces
  • метаданные: severity, owner, links
  • Это особенно полезно в проекте, где вместе живут UI и API.

    Документация:

  • Allure Framework documentation
  • Allure Pytest integration
  • Установка и генерация отчёта

    Установка Python-плагина:

    Запуск с генерацией результатов:

    Локальный просмотр (нужен установленный Allure Commandline):

    В CI чаще делают так:

  • собирают allure-results как артефакт
  • либо генерируют allure-report и публикуют
  • Добавление шагов Allure без “замусоривания” Page Object

    Главная идея архитектуры курса: тест должен быть читаемым, а Page Object не должен превращаться в “репортинг-фреймворк”.

    Практичный компромисс:

  • Allure-шаги ставим в тестах вокруг крупных бизнес-шагов
  • внутри Page Object оставляем чистые методы без привязки к Allure
  • Пример:

    Плюс: отчёт становится понятным менеджерам и аналитикам.

    Прикрепление скриншота на падении в Allure

    Скриншоты полезны даже при наличии trace и видео, потому что это самый быстрый способ увидеть “что на экране”.

    Пример фикстуры, которая делает скриншот при падении теста и добавляет в Allure:

    Важно:

  • такой подход работает только если страница ещё жива в момент teardown
  • если вы закрываете page раньше, прикрепление нужно делать до закрытия
  • Как прикреплять trace в Allure

    Trace обычно это .zip. Его можно прикрепить как файл:

  • сохраняете trace по падению в artifacts/traces/...zip
  • на teardown добавляете allure.attach.file(path, ...)
  • Дальше инженер скачивает zip и открывает Trace Viewer локально.

    Тестовые окружения: как не сломать проект конфигами

    Что такое тестовое окружение

    Окружение это набор параметров, от которых зависит тест:

  • URL фронтенда и API
  • токены/ключи
  • настройки браузера
  • фиче-флаги
  • тестовые аккаунты
  • Главная опасность: окружения начинают задаваться “как попало”, и тесты становятся невоспроизводимыми.

    Принципы конфигурации

    Рекомендуемые правила:

  • все настройки читаются из переменных окружения
  • дефолты существуют только для локального запуска
  • секреты не коммитятся
  • UI и API имеют отдельные базовые URL
  • Расширенный utils/config.py в стиле курса может содержать:

    Дальше фикстуры base_url и api_client используют settings.

    Маркеры и тест-пирамиды по окружениям

    Практичная модель запусков:

  • smoke гоняем на каждый Pull Request
  • regression гоняем по расписанию или перед релизом
  • ui и api можно разводить по разным джобам
  • Пример команд:

    CI/CD пайплайн: минимально жизнеспособный вариант

    Ниже пример для GitHub Actions, который:

  • ставит зависимости
  • ставит браузеры Playwright
  • запускает API и UI
  • сохраняет артефакты
  • Документация:

  • GitHub Actions documentation
  • Playwright: CI guide
  • Пример workflow

    .github/workflows/tests.yml:

    Что важно в этом пайплайне:

  • if: always() гарантирует загрузку артефактов даже при падениях
  • секреты берутся из secrets, а не из репозитория
  • артефакты складываются в одну предсказуемую папку
  • Параллельный запуск в CI

    Если UI-тестов много, добавляют pytest-xdist.

    Пример команды:

    Ограничение:

  • параллельность требует уникализации тестовых данных
  • если тесты создают сущности, лучше готовить данные через API и делать уникальные значения
  • Разделение UI и API по джобам

    Когда проект растёт, обычно выгодно разделить:

  • быстрые API-тесты отдельно
  • UI-тесты отдельно
  • Плюсы:

  • быстрее обратная связь по API
  • проще дебажить флейк UI
  • Минус:

  • нужно аккуратнее управлять общими артефактами и Allure
  • Практические стандарты качества для проекта курса

    Ниже набор решений, который хорошо работает “по умолчанию”:

  • Allure включён всегда: --alluredir=artifacts/allure-results
  • UI-артефакты по падениям: --tracing=retain-on-failure --video=retain-on-failure --screenshot=only-on-failure
  • артефакты всегда upload в CI
  • конфиги только через переменные окружения
  • smoke и regression разделены маркерами
  • !Рекомендуемая структура хранения артефактов рядом с тестовым проектом

    Итог

    Вы собрали “операционную” часть автотест-проекта, без которой код тестов не превращается в работающий процесс:

  • научились выбирать базовые форматы отчётности Pytest и JUnit XML
  • поняли, как и зачем включать trace, видео и скриншоты Playwright
  • подключили Allure как единый отчёт для UI и API и разобрали стратегию шагов и вложений
  • закрепили принципы тестовых окружений через переменные окружения
  • получили минимальный CI/CD пайплайн, который ставит зависимости, запускает тесты и сохраняет артефакты