Аннотации тестов
Урок: Аннотации тестов
Введение
Представь, что у тебя есть список задач на день. Какие-то задачи срочные, какие-то можно отложить, какие-то вообще пока не актуальны. Чтобы не запутаться, ты начинаешь помечать их:
- «срочно»
- «позже»
- «не делать»
Такие пометки помогают быстро ориентироваться и управлять работой.
В тестировании происходит похожая ситуация. Не все тесты одинаковые:
- какие-то ещё не готовы;
- какие-то временно падают;
- какие-то нужно запускать только в определённых условиях.
Чтобы управлять этим, в Playwright используются аннотации тестов.
Аннотации — это специальные пометки, которые изменяют поведение тестов.
Официальный обзор: Annotations | Playwright. Низкоуровневые методы на объекте test: test.skip / fail / fixme / slow / only.
Что такое аннотации тестов
Аннотации — это способы сказать раннеру Playwright Test, как относиться к тесту или к группе.
Встроенные (меняют запуск и таймауты):
test.skip— тест не выполняется (помечен как нерелевантный);test.fail— тест должен упасть; если вдруг прошёл — это ошибка прогона;test.fixme— тест помечен как сломанный и не запускается (в отличие отfail, где тест всё же бежит);test.slow— помечает тест как медленный и утраивает таймаут теста;test.only— при наличии хотя бы одногоonlyвыполняются только такие тесты в проекте.
Часть аннотаций можно задавать условно (зависят от фикстур вроде browserName, isMobile и т.д.).
Простой пример:
test.skip('этот тест пропущен', async ({ page }) => {
// код теста
});
Здесь:
test.skip— это аннотация;- тест не будет выполняться.
Важно: аннотация не меняет код теста, а меняет его поведение.
Пропуск тестов (skip)
Иногда тест временно не нужен или не работает.
test.skip('логин временно отключён', async ({ page }) => {
await page.goto('/login');
});
Что происходит:
- тест игнорируется;
- не запускается вообще.
Это полезно, когда:
- функциональность в разработке;
- тест временно падает;
- нужно исключить тест из прогона.
Условный skip
Условный пропуск задаётся внутри тела теста (или в начале describe): первый аргумент — условие, второй — причина в отчёте.
test('не в Firefox пока', async ({ page, browserName }) => {
test.skip(browserName === 'firefox', 'Дорабатываем под Firefox');
await page.goto('/app');
// ...
});
Если условие истинно, оставшаяся часть теста не выполняется. Так удобно отключать сценарии под браузер, мобильный вид, флаги окружения и т.д.
Пропустить всю группу по условию можно так (первой строкой внутри describe):
test.describe('только Chromium', () => {
test.skip(({ browserName }) => browserName !== 'chromium', 'Нужен Chromium');
test('один', async ({ page }) => {
/* ... */
});
});
См. Conditionally skip a group of tests.
Только этот тест (only)
Иногда нужно запустить один конкретный тест.
test.only('проверка логина', async ({ page }) => {
await page.goto('/login');
});
Что происходит:
- в прогоне участвуют только тесты с
test.only/test.describe.only(если они есть); - остальные тесты не запускаются.
Это удобно при локальной отладке. Важно: не коммитить only — в CI так можно случайно прогнать долю набора и получить «зелёный» ложный результат.
Пометка ожидаемой ошибки (fail)
Иногда ты знаешь, что тест сейчас падает, но это ожидаемо.
test.fail('известный баг', async ({ page }) => {
await page.goto('/broken-page');
});
Что происходит:
- если тест упадёт — он будет считаться «успешным»;
- если неожиданно пройдёт — будет считаться ошибкой.
Это помогает:
- отслеживать известные баги;
- понимать, когда проблема исправлена.
fixme — тест не запускается
test.fixme() по смыслу близок к «сломано, чиним»: тест не выполняется, в отличие от test.fail, где сценарий запускается и ожидается падение.
test.fixme('падает на CI из-за тайминга', async ({ page }) => {
// не бежит, пока не снимешь fixme
});
Условный вариант — внутри теста или хука:
test.beforeEach(async ({ page, isMobile }) => {
test.fixme(isMobile, 'Настройки на мобильном пока не готовы');
await page.goto('/settings');
});
См. Use fixme in beforeEach hook.
Медленные тесты (test.slow)
Для отдельно тяжёлых сценариев в теле теста вызывают test.slow() — таймаут теста утраивается (см. test.slow).
test('долгий импорт данных', async ({ page }) => {
test.slow();
await page.goto('/reports/heavy');
// ...
});
Не путать с test.setTimeout в хуках — это разные механизмы; test.slow() нельзя вызывать в beforeAll / afterAll (для хуков используют test.setTimeout внутри хука).
Групповые аннотации через describe
Аннотации можно применять к группе тестов.
test.describe('логин', () => {
test.skip('тест 1', async () => {});
test('тест 2', async () => {});
});
Или ко всей группе:
test.describe.skip('логин', () => {
test('тест 1', async () => {});
test('тест 2', async () => {});
});
Здесь все тесты внутри блока пропущены. Аналогично существуют test.describe.only, test.describe.fail и др. — см. test.describe.
Теги и фильтрация (--grep)
Теги задают в названии (@slow в строке) или в опциях при объявлении — затем их подхватывает отчёт и CLI.
test('смоук логина', { tag: '@smoke' }, async ({ page }) => {
// ...
});
test('полный отчёт @slow @vrt', async ({ page }) => {
// ...
});
test.describe('отчёты', { tag: '@report' }, () => {
test('заголовок', async ({ page }) => {
/* ... */
});
});
Запуск только тестов с тегом:
npx playwright test --grep @smoke
Исключить тег, логическое ИЛИ и И — в Tag tests. В конфиге можно использовать grep / grepInvert на уровне проекта.
Аннотации при объявлении теста
Помимо тегов можно задать тип и описание — они попадают в HTML-отчёт и API репортёра (типы, начинающиеся с _, скрываются в встроенном отчёте).
test('страница входа', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/23180',
},
}, async ({ page }) => {
// ...
});
Несколько аннотаций — массивом в annotation: [ … ]. См. Annotate tests.
Метаданные во время прогона (test.info())
Во время выполнения теста можно дописать аннотации в test.info().annotations (например, версию браузера):
test('пример', async ({ page, browser }) => {
test.info().annotations.push({
type: 'browser version',
description: browser.version(),
});
// ...
});
См. Runtime annotations.
Пример из реального сценария
test.describe('авторизация', () => {
test.skip('логин через соцсети', async ({ page }) => {
// временно отключён
});
test('логин через email', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('test@mail.com');
await page.getByLabel('Пароль').fill('1234');
await page.getByRole('button', { name: 'Войти' }).click();
await expect(page.getByText('Добро пожаловать')).toBeVisible();
});
});
Что здесь важно:
- один тест отключён;
- другой выполняется;
- структура понятна.
Почему аннотации важны
Без аннотаций:
- сложно управлять тестами;
- приходится удалять или комментировать код;
- трудно отслеживать состояние тестов.
С аннотациями:
- можно гибко управлять выполнением;
- тесты остаются в коде;
- легче понимать, что происходит.
Где это используется на практике
Аннотации активно используются:
- при разработке тестов;
- при работе с багами;
- в CI/CD;
- в больших проектах.
Например:
- временно отключить тест;
- пометить известную проблему;
- запустить только нужный сценарий;
- адаптировать тесты под окружение.
Итоговое понимание
Аннотации тестов — это способ управлять поведением тестов без размазывания логики по if вокруг всего файла.
Ключевые приёмы из документации Playwright:
skip/only/ условныйskipв теле теста или вdescribe;failпротивfixme(запуск с ожиданием падения vs отключение);slowдля увеличения таймаута;- теги и
--grepдля выборочных прогонов; - аннотации при объявлении и runtime через
test.info().annotations.
Хорошее использование аннотаций делает набор тестов гибким, прозрачным в отчётах и удобным для команды — при этом важно не оставлять only и не злоупотреблять fixme вместо починки тестов.