Структура: 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 — для разовой подготовки, но осторожно с общим состоянием.
Проверьте себя
1. Зачем нужен хук beforeEach?
AЧтобы запустить тесты параллельно
BЧтобы выполнить повторяющуюся подготовку перед каждым тестом
CЧтобы пропустить тест
DЧтобы сгенерировать отчёт
2. Что делает test.describe?
AПропускает группу тестов
BГруппирует связанные тесты и позволяет навесить общую подготовку
CЗапускает тесты только в Chromium
DСоздаёт новый браузер
3. Чем опасен забытый test.only перед коммитом?
AОн удалит остальные тесты
BВ CI прогонится только этот тест, а остальные будут пропущены
CТест начнёт падать
DНичем, это безопасно
Поддержать проект