Что это решает
Есть класс работы, где человек каждый день делает в браузере одно и то же: открыть админку, выставить период, нажать «Выгрузить», переложить файл в папку. Или после каждого выката пройти пять экранов и убедиться, что регистрация и оплата живы. Playwright снимает именно это: сценарий описывается кодом один раз и дальше выполняется в настоящем браузере — с рендерингом, JavaScript, куками и всем, что видит живой пользователь. Второй закрываемый случай — доступ к данным там, где API нет или он закрыт: если цифра существует только на экране, её можно забрать со страницы программно.
Как устроено
Из чего состоит
Пакет ставится в проект командой npm i -D @playwright/test, браузеры качаются отдельно — npx playwright install. Скачиваются собственные сборки Chromium, Firefox и WebKit зафиксированных версий. Системный Chrome по умолчанию не используется, чтобы прогон на ноутбуке и прогон в CI шли на одном и том же движке и падали одинаково. На голом Linux-сервере обычно нужен npx playwright install --with-deps — он доставит системные библиотеки, без которых браузер не стартует и выдаёт невнятную ошибку загрузки.
Три уровня объектов
browser — запущенный процесс браузера. context — изолированный профиль внутри него: свои cookie, свой localStorage, свой размер окна, своя локаль и геолокация. page — вкладка. Контекст создаётся за миллисекунды, поэтому правильный способ развести сценарии — новый контекст, а не новый браузер. Один залогиненный контекст под менеджера, второй под клиента — в одном прогоне, без конфликта сессий и без второго компьютера.
Локаторы и ожидание
Запись page.getByRole('button', { name: 'Оплатить' }) описывает, как найти элемент, а не находит его сразу. Реальный поиск происходит в момент действия. Перед кликом библиотека проверяет: элемент есть в DOM, видим, не перекрыт другим элементом, перестал двигаться, принимает события. Только после этого бьёт по координатам. Из-за этого из сценариев уходят паузы вида «подождать три секунды» — главный источник плавающих падений. Проверка expect(locator).toHaveText(...) работает так же: перечитывает страницу, пока условие не совпадёт или не кончится таймаут.
Порядок предпочтений при поиске элемента: роль и видимое имя (getByRole), подпись поля (getByLabel), текст (getByText), явно проставленный атрибут (getByTestId). CSS- и XPath-пути вроде div > div:nth-child(3) > span работают ровно до первой правки вёрстки, после чего сценарий падает на пустом месте.
Раннер и конфиг
Файл playwright.config.ts задаёт базовый URL, таймауты, число параллельных воркеров, retries для перезапуска упавшего теста, набор projects (один и тот же сценарий на трёх браузерах или на мобильном вьюпорте) и блок webServer — команду, которой поднять приложение перед прогоном, и адрес, по которому ждать готовности. Тестовые файлы раскидываются по воркерам, поэтому сценарии обязаны быть независимы: любой порядок выполнения должен давать один результат.
Трасса
При настройке trace: 'on-first-retry' упавший тест перезапускается с записью. На выходе zip-архив: снимок DOM на каждом шаге, сетевые запросы, консоль, скриншоты до и после действия. Команда npx playwright show-trace trace.zip открывает это таймлайном, по которому видно, на каком шаге страница выглядела не так, как ожидал код. Чтение трассы почти всегда быстрее, чем повторный ручной прогон с попыткой поймать момент.
Сеть и авторизация
Вызов page.route('**/api/**', route => ...) перехватывает запросы: подменить ответ, отдать заготовленный JSON, заблокировать внешнюю аналитику, которая тормозит прогон и шумит в трассе. Метод context.storageState({ path: 'auth.json' }) сохраняет куки и localStorage после логина; дальше контексты создаются с этим файлом и стартуют уже авторизованными. Логин выполняется один раз в подготовительном проекте, а не в каждом сценарии — экономия минут на каждом прогоне.
Запись черновика
Команда npx playwright codegen https://example.com открывает браузер и пишет код по кликам. Черновик почти всегда требует правки — селекторы генератор берёт как получится, — но каркас сценария появляется за минуты, и дальше руками остаётся поменять способ поиска элементов на устойчивый.
Полезные сценарии
- Смоук после выката: открыть главную, залогиниться, создать заказ, убедиться, что он появился в списке — пара минут машинного времени вместо ручного обхода.
- Выгрузка из панели без API: авторизоваться, выставить период, нажать экспорт, поймать файл через
page.waitForEvent('download')и положить в нужную папку. - Мониторинг критического пути по расписанию: тот же сценарий раз в час из cron, падение — сообщение в мессенджер.
- Скриншоты страниц в двух темах и трёх вьюпортах (
page.screenshot({ fullPage: true })) для сверки до и после редизайна. - Проверка заявки от лица клиента: заполнить форму, отправить, убедиться, что письмо ушло и запись легла в базу.
- Разбор жалобы «у меня не работает»: прогнать сценарий с записью трассы и посмотреть, что реально вернул сервер в тот момент.
Ограничения
Сценарий держится на разметке. Поменяли текст кнопки — упало. За набором сценариев нужен хозяин, иначе через пару месяцев половина красная, на красное перестают смотреть, и вся затея превращается в шум.
Антибот-защита и капча останавливают автоматизацию по замыслу. Для чужих сайтов дополнительно смотрят условия использования — техническая возможность и право на действие тут разные вещи. Двухфакторная авторизация тоже требует решения: либо сервисный аккаунт без второго фактора, либо ручной первичный логин с сохранением storageState и регулярным обновлением файла.
Браузер стоит ресурсов. Каждый параллельный воркер — процесс с сотнями мегабайт памяти; на маленьком CI-раннере десяток воркеров кладёт сборку по нехватке памяти. Прогоны считаются минутами, а не секундами.
Где есть API — данные берут через API. Разбор HTML вместо готового JSON-эндпоинта медленнее и ломается чаще, потому что вёрстка меняется без предупреждения, а контракт эндпоинта обычно нет.
Браузерная проверка говорит «форма не отправилась», но молчит о том, в какой функции ошибка. Полагаться только на неё дорого по времени прогона и мучительно при разборе.
Отдельная забота — секреты. Пароль сервисного аккаунта не должен лежать в репозитории: переменные окружения и хранилище секретов CI, файл auth.json — в .gitignore.
Как проверить результат
Прогон в видимом режиме: npx playwright test --headed или --ui, где виден каждый шаг и можно отмотать назад. Если сценарий проходит в видимом режиме и падает в фоновом, дело почти всегда в размере окна или в анимации, которую в фоне никто не ждёт.
Проверка на стабильность: npx playwright test --repeat-each=5 гоняет один и тот же сценарий пять раз подряд. Тест, который падает один раз из пяти, чинят сразу — в CI он будет краснеть случайно и обесценит весь набор.
Трасса на первом падении: включить trace: 'on-first-retry', дождаться падения в CI, скачать артефакт, открыть просмотрщик. Смотреть на шаг, где действие не нашло элемент, и рядом на сетевую вкладку — часто виноват не селектор, а 500 от сервера.
Код возврата и отчёт: упавший прогон обязан возвращать ненулевой код и останавливать пайплайн. npx playwright show-report открывает HTML-отчёт с шагами, скриншотами и временем каждого действия.
Учебное падение: сломать что-нибудь нарочно на тестовом стенде — поменять текст кнопки, вернуть 500 на нужном маршруте — и убедиться, что сценарий покраснел. Набор проверок, который ни разу не падал, ничего не доказывает про систему; он доказывает только то, что проверок нет.
