Структура: test, describe и хуки
Группируем тесты и выносим повторяющуюся подготовку в хуки.
Хук (hook) — функция, которую Playwright запускает до или после тестов: например, чтобы открыть нужную страницу перед каждым тестом.
Базовый блок: test
Каждый тест объявляется через test('описание', async ({ page }) => {...}). Описание должно читаться как фраза о поведении: «отображает ошибку при пустом email». Хорошее имя теста — это половина отчёта: по нему сразу понятно, что сломалось.
import { test, expect } from '@playwright/test';
test('главная страница показывает заголовок', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Магазин' })).toBeVisible();
});Группировка: describe
Связанные тесты объединяют в группу test.describe. Это улучшает читаемость отчёта и позволяет навесить общую подготовку на всю группу.
test.describe('Страница входа', () => {
test('пускает с верными данными', async ({ page }) => {
// ...
});
test('показывает ошибку с неверным паролем', async ({ page }) => {
// ...
});
});Хуки: убираем дублирование
Если каждый тест в группе начинается с одних и тех же шагов (зайти на страницу, авторизоваться), вынесите их в хук beforeEach — он выполнится перед каждым тестом группы.
test.describe('Личный кабинет', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Пароль').fill('secret');
await page.getByRole('button', { name: 'Войти' }).click();
await expect(page).toHaveURL('/dashboard');
});
test('показывает имя пользователя', async ({ page }) => {
await expect(page.getByText('Иван Петров')).toBeVisible();
});
test('есть кнопка выхода', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Выйти' })).toBeVisible();
});
});Теперь оба теста стартуют уже на странице кабинета, не повторяя шаги входа. Это и короче, и надёжнее: логика входа описана в одном месте.
Четыре хука
| Хук | Когда выполняется |
beforeEach | перед каждым тестом — самый частый |
afterEach | после каждого теста — очистка |
beforeAll | один раз до всех тестов группы |
afterAll | один раз после всех тестов группы |
beforeAll и afterAll выполняются однократно — удобно для тяжёлой разовой подготовки. Но осторожно: то, что создано в beforeAll, разделяется между тестами, а это риск зависимостей. Для большинства случаев предпочтительнее beforeEach с чистым состоянием.
Полезные модификаторы
test.skip('пока не реализовано', async ({ page }) => { /* ... */ });
test.only('запустить только этот', async ({ page }) => { /* ... */ });
test.fixme('сломан, чиним', async ({ page }) => { /* ... */ });test.only удобен при отладке, но не забудьте убрать его перед коммитом — иначе в CI прогонится один тест вместо всех, и вы получите «зелёный» прогон, который ничего не проверил.
Итог
test— один сценарий; описание читается как фраза о поведении.test.describeгруппирует связанные тесты.beforeEachубирает дублирование подготовки — самый частый хук.beforeAll/afterAll— для разовой подготовки, но осторожно с общим состоянием.