Данные, изоляция и авторизация один раз

Изоляция и тестовые данные определяют, будут ли тесты стабильными. А авторизацию можно сделать один раз на весь прогон.

Storage state — сохранённое состояние сессии (cookie и localStorage), которое можно записать один раз после входа и подставлять в тесты, минуя повторную авторизацию.

Изоляция: каждый тест с чистого листа

Playwright по умолчанию даёт каждому тесту свежий контекст — без чужих cookie и данных. Это значит, что тесты не влияют друг на друга и могут идти в любом порядке и параллельно. Не нарушайте это: не полагайтесь на данные, оставленные другим тестом, иначе вернётся проблема флаки из прошлого раздела.

Тестовые данные: делайте их уникальными

Если два теста регистрируют пользователя с email [email protected], при параллельном запуске один из них упадёт — email уже занят. Решение — уникальные данные на каждый прогон.

// уникальный email на основе времени
const email = `user-${Date.now()}@example.com`;
await page.getByLabel('Email').fill(email);

Проблема: вход в каждом тесте — это дорого

Если двадцать тестов начинаются с beforeEach, где происходит вход (заполнить форму, нажать кнопку, дождаться редиректа), вы платите за авторизацию двадцать раз. На большом наборе это заметные минуты, потраченные впустую на одни и те же шаги.

Решение: авторизоваться один раз

Идея: войти однажды в setup-проекте, сохранить состояние сессии в файл, а все тесты запускать уже с этим состоянием. Сначала setup-тест, который логинится и сохраняет storage state:

// auth.setup.ts
import { test as setup } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('авторизация', 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 page.waitForURL('/dashboard');

  // сохраняем cookie и localStorage в файл
  await page.context().storageState({ path: authFile });
});

Затем в конфиге указываем: брать это состояние для всех тестов, а setup выполнять до них.

// playwright.config.ts (фрагмент)
projects: [
  { name: 'setup', testMatch: /auth\.setup\.ts/ },
  {
    name: 'chromium',
    use: { storageState: 'playwright/.auth/user.json' },
    dependencies: ['setup'],   // сначала setup, потом тесты
  },
],

Теперь каждый тест стартует уже авторизованным — без формы входа. Вход выполнился один раз.

test('видит личный кабинет', async ({ page }) => {
  await page.goto('/dashboard');  // уже залогинены!
  await expect(page.getByText('Иван Петров')).toBeVisible();
});

Что хранить отдельно

СценарийПодход
Обычный пользовательодин storage state на всех
Разные роли (admin, user)отдельный файл состояния на роль
Тест самого входа/выходабез storage state, логиниться в тесте

Тесты, которые проверяют сам процесс входа, разумеется, должны логиниться вручную — для них переиспользование сессии не подходит, иначе они проверяли бы не то. И не забудьте добавить папку playwright/.auth/ в .gitignore: в ней лежат настоящие токены сессии.

Итог

  • Каждый тест получает чистый контекст — не полагайтесь на чужие данные.
  • Делайте тестовые данные уникальными (например, email с меткой времени).
  • Storage state позволяет авторизоваться один раз и переиспользовать сессию.
  • Для разных ролей — разные файлы состояния; тесты входа логинятся вручную.
Проверьте себя
1. Что хранит storage state?
AСкриншоты всех тестов
BCookie и localStorage сессии, чтобы не логиниться заново
CИсходный код страницы
DСписок локаторов
2. Почему тестовые данные стоит делать уникальными на каждый прогон?
AТак быстрее работает браузер
BИначе при параллельном запуске возникнут конфликты, например занятый email
CЭто требование синтаксиса Playwright
DУникальность отключает авто-ожидания
3. Как авторизоваться один раз на весь набор тестов?
AВызывать login в beforeEach каждого теста
BВойти в setup-проекте, сохранить storage state и подключить его через dependencies
CОтключить изоляцию контекстов
DЗахардкодить cookie прямо в тесте
Поддержать проект