Модуль 2 · Автоматизация · урок 5 из 13
E2E на Playwright с Codex
E2E-тесты — место, где агент экономит больше всего часов и где он же чаще всего хитрит. Написать спек на Playwright Codex может за минуту, а вот сделать его устойчивым и честным — задача для вас двоих. Разберём рабочий цикл на примере сайта на OctoberCMS с регресс-набором в tests/e2e.
Контекст, без которого будет плохо
Перед первой задачей убедитесь, что агенту доступно:
playwright.config.ts—baseURL, проекты (например, десктоп и мобильный Chromium), ретраи, трейсы. Агент должен понимать, что каждый тест прогонится и в мобильном проекте.- Существующие спеки и
tests/e2e/support— общие хелперы, проверка «работаем только на localhost», фикстуры. Иначе агент напишет свои с нуля. - Правила в AGENTS.md — локаторы, запреты, критерий «готово» (см. урок «Настройка Codex под тестирование»).
И отдельно — шаблоны страниц. В OctoberCMS разметка лежит в .htm-файлах темы и partials. Если агент видит шаблон, он находит реальные подписи кнопок и полей, а не угадывает button.submit-btn.
Цикл: кейс → спек → прогон → разбор
Начинайте с проверки, сформулированной словами, — например, из тест-дизайна:
Напиши e2e-тест в tests/e2e/feedback-form.spec.ts по кейсам TC-01…TC-04
(ниже). Перед написанием открой шаблон формы в теме и найди реальные
подписи полей и кнопки. Используй хелперы из tests/e2e/support.
Прогони: npx playwright test tests/e2e/feedback-form.spec.ts
Если тест падает — сначала объясни причину, потом правь.
Нельзя: waitForTimeout, force: true, ослабление утверждений.Фраза «сначала объясни причину» дисциплинирует. Без неё агент склонен менять тест, пока тот не позеленеет, не понимая, почему он падал.
Результат, к которому стоит стремиться:
import { test, expect } from '@playwright/test';
test.describe('Форма обратной связи', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/contacts');
});
test('не отправляется без имени и показывает ошибку у поля', async ({ page }) => {
const form = page.getByRole('form', { name: 'Обратная связь' });
await form.getByLabel('Email').fill('qa@example.test');
await form.getByRole('button', { name: 'Отправить' }).click();
await expect(form.getByText('Укажите имя')).toBeVisible();
await expect(page.getByText('Спасибо, заявка отправлена')).toBeHidden();
});
test('принимает телефон вместо email', async ({ page }) => {
const form = page.getByRole('form', { name: 'Обратная связь' });
await form.getByLabel('Имя').fill('Тест');
await form.getByLabel('Телефон').fill('+7 999 123-45-67');
await expect(form.getByRole('button', { name: 'Отправить' })).toBeEnabled();
});
});Обратите внимание: утверждения веб-ориентированные (web-first assertions, await expect(locator)…) — Playwright сам ждёт нужного состояния, и ручные паузы не нужны. Во втором тесте нет отправки формы: тесты, которые реально создают заявку, в таком проекте разрешены только на локальном стенде, и агент должен использовать для них общий хелпер, а не отправлять что попало.
Локаторы и роли
Просите локаторы по ролям и подписям: getByRole, getByLabel, getByText. Это заодно проверка доступности: если у поля нет подписи, getByLabel его не найдёт — и это баг вёрстки, а не повод для CSS-селектора. Попросите агента в таких случаях не обходить проблему, а записать её отдельно.
Если локатор находит несколько элементов, Playwright падает с нарушением строгого режима (strict mode violation). Частая «починка» агента — добавить .first(). Иногда это верно, но чаще означает, что локатор неточен и тест кликает не туда, куда вы думаете. Требуйте сузить область: найти элемент внутри формы или секции.
Как агент «чинит» тесты и почему это опасно
Вот что встречается в диффах регулярно — и что нужно отклонять:
| Что сделал агент | Чем опасно |
|---|---|
await page.waitForTimeout(3000) |
Медленно и всё равно нестабильно; прячет гонку |
click({ force: true }) |
Кликает по перекрытому элементу — пользователь так не может |
Увеличил timeout или retries |
Маскирует медленную страницу или флак |
Заменил toHaveText('…') на toBeVisible() |
Тест больше не проверяет содержимое |
Обернул шаг в try/catch |
Ошибка проглатывается, тест зелёный всегда |
Добавил test.skip |
Проблема исчезла из отчёта, но не из продукта |
Хорошая привычка — после каждой сессии смотреть дифф тестов отдельно от кода: git diff -- tests/. Подробно о проверке — в уроке «Как проверять тесты, написанные агентом».
Разбор падений
Когда тест падает, агенту нужен не только текст ошибки. Playwright складывает в test-results скриншот и вложения упавшего теста, а при настройке trace: 'on-first-retry' — ещё и трейс. Попросите агента прочитать ошибку и вложения и сформулировать гипотезу: «элемент не появился», «появился, но с другим текстом», «перекрыт модальным окном куки». Трейс удобнее смотреть вам самим: npx playwright show-trace <путь к trace.zip>.
Если тест падает только в мобильном проекте, это часто не баг теста, а реальная проблема адаптива: меню свёрнуто в бургер, кнопка ушла за край экрана. Не давайте агенту исключить мобильный проект «для стабильности».
Запись сценариев браузером
Иногда быстрее показать сценарий, чем описать. У Playwright есть npx playwright codegen для записи действий человеком. Агент может пройти сценарий сам через браузер — встроенный или Playwright MCP — и потом написать тест по тому, что увидел. В Playwright MCP есть дополнительные возможности для тестов, например генерация локатора для элемента; они включаются флагом --caps. README Playwright MCP при этом прямо советует кодинг-агентам рассмотреть Playwright CLI с навыками как более экономный по токенам путь (playwright-mcp). Подробнее — в уроке «Браузер в руках агента».
Попробуйте сами
10–15 мин на рабочем месте- Возьмите один ручной кейс и попросите агента написать по нему спек с запретами из урока. Проверьте, что он прогнал тест в обоих проектах из конфига.
- Сломайте в шаблоне подпись кнопки, прогоните тест и посмотрите, что агент предложит: исправить тест или сообщить о расхождении.
- Выполните
git diff -- tests/после сессии и найдите хотя бы одно место из таблицы «починок», если оно есть.
Коротко
- Агенту нужны конфиг Playwright, существующие хелперы, правила из AGENTS.md и шаблоны страниц.
- Локаторы по ролям и подписям; отсутствие подписи — баг вёрстки, а не повод для CSS-селектора.
- Веб-ориентированные утверждения вместо пауз;
force,waitForTimeout,try/catchиskip— отклонять. - При падении — сначала причина, потом правка; дифф тестов смотреть отдельно.
- Падение только в мобильном проекте — частый признак настоящего бага адаптива.