playwright.config.ts задаёт таймаут теста, количество повторов, число параллельных воркеров, поведение трейсинга и base URL для всего сьюта. Дефолты от npm init playwright@latest работают локально, но у них два CI-подводных камня: workers: undefined вызывает конкуренцию за ресурсы на общих раннерах, а отсутствие forbidOnly: !!process.env.CI позволяет случайно закоммиченному test.only() тихо пропустить весь сьют. Эта статья разбирает каждую опцию которую используешь в реальном проекте и заканчивается готовым к продакшну конфигом с настройкой аутентификации, URL под разные окружения и отдельными репортерами для локальной разработки и CI.

Минимальный конфиг

После npm init playwright@latest получишь что-то вроде:

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
  ],
});

Разберём каждую секцию.

Верхнеуровневые опции

testDir

Где Playwright ищет тест-файлы.

testDir: './tests',

Относительный или абсолютный путь. Файлы по маскам /.spec.ts и /.test.ts внутри этой папки подхватываются автоматически.

fullyParallel

fullyParallel: true,

При true: все тесты запускаются параллельно на воркерах, даже тесты в одном файле. При false (прежний дефолт): тесты внутри файла запускаются последовательно, но разные файлы в параллели.

Для большинства проектов ставь true. Тесты должны быть достаточно независимы, чтобы работать в любом порядке.

forbidOnly

forbidOnly: !!process.env.CI,

Если тест помечен test.only(), весь прогон завершится с ошибкой. Паттерн !!process.env.CI применяет это правило только в CI: локально можно использовать test.only() при отладке, но случайно его закоммитить не получится.

Всегда добавляй в продакшн-конфиги.

retries

retries: process.env.CI ? 2 : 0,

Сколько раз повторять упавший тест перед тем как признать его провальным. В CI: 2 повтора (помогает с флакующими тестами). Локально: 0 (чтобы сразу видеть падения).

Если тест падает с первого раза но проходит при повторе, Playwright помечает его как "flaky" в отчёте.

workers

workers: process.env.CI ? 1 : undefined,

Количество параллельных воркеров (экземпляров браузера): undefined (дефолт) использует 50% ядер CPU, 1 запускает все тесты последовательно (полезно в CI чтобы избежать конкуренции за ресурсы), 4 означает 4 параллельных воркера.

Для локальной разработки на мощной машине undefined подходит. В CI безопаснее 1, если только раннер не особо производительный.

timeout

timeout: 30_000,  // 30 секунд на тест

Максимальное время выполнения одного теста. Дефолт: 30 секунд. Для медленных тестов или медленных CI-машин увеличивай до 60 секунд.

expect.timeout

expect: {
  timeout: 5_000,  // 5 секунд на каждый expect()
},

Ассёрты в Playwright повторяются автоматически: до выполнения условия или до истечения таймаута. Дефолт: 5 секунд.

Блок use (общие настройки тестов)

use содержит опции которые применяются ко всем тестам (если не переопределены проектом).

use: {
  baseURL: 'http://localhost:3000',
  
  // Настройки браузера
  headless: true,
  viewport: { width: 1280, height: 720 },
  
  // Запись
  trace: 'on-first-retry',     // 'on-first-retry' | 'retain-on-failure' | 'always' | 'off'
  video: 'retain-on-failure',  // 'retain-on-failure' | 'always' | 'off'
  screenshot: 'only-on-failure',
  
  // Таймауты
  actionTimeout: 10_000,       // таймаут для каждого действия (click, fill и т.д.)
  navigationTimeout: 30_000,   // таймаут для page.goto() и page.waitForURL()
  
  // HTTP
  ignoreHTTPSErrors: true,     // полезно для staging с самоподписанными сертификатами
  
  // Локаль
  locale: 'en-US',
  timezoneId: 'America/New_York',
},

baseURL

Когда задан, page.goto('/login') разрешается в http://localhost:3000/login. Делает тесты переносимыми между окружениями.

Используй переменную окружения:

baseURL: process.env.BASE_URL || 'http://localhost:3000',

trace

Трейсы Playwright записывают полную историю каждого действия: снимки DOM, скриншоты, сетевые запросы. Опции:

  • 'on-first-retry': записывает при первом повторе упавшего теста. Рекомендуется.
  • 'retain-on-failure': записывает при любом провале (больше места на диске)
  • 'always': записывает всё (много места, медленнее)
  • 'off': без трейсов

Просмотр: npx playwright show-trace trace.zip.

video

'retain-on-failure' сохраняет видео только для упавших тестов (рекомендуется), 'always' сохраняет всё, 'off' отключает запись.

projects: несколько конфигураций браузеров

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

projects: [
  // Десктопные браузеры
  {
    name: 'chromium',
    use: { ...devices['Desktop Chrome'] },
  },
  {
    name: 'firefox',
    use: { ...devices['Desktop Firefox'] },
  },
  {
    name: 'webkit',
    use: { ...devices['Desktop Safari'] },
  },
  
  // Мобильные
  {
    name: 'mobile-chrome',
    use: { ...devices['Pixel 7'] },
  },
  {
    name: 'mobile-safari',
    use: { ...devices['iPhone 14'] },
  },
],

devices['Desktop Chrome']: пресет с заданным вьюпортом, user agent и другими браузерными дефолтами. Полный список смотри через npx playwright show-report или в документации Playwright.

Проекты для разных окружений

projects: [
  {
    name: 'staging',
    use: {
      ...devices['Desktop Chrome'],
      baseURL: 'https://staging.myapp.com',
    },
    testMatch: '**/*.spec.ts',
  },
  {
    name: 'production',
    use: {
      ...devices['Desktop Chrome'],
      baseURL: 'https://myapp.com',
    },
    testMatch: '**/smoke/*.spec.ts',  // только smoke-тесты в продакшне
  },
],

Setup-проекты (глобальная подготовка)

projects: [
  {
    name: 'setup',
    testMatch: /.*\.setup\.ts/,  // файлы вроде auth.setup.ts
  },
  {
    name: 'chromium',
    use: { ...devices['Desktop Chrome'] },
    dependencies: ['setup'],  // сначала запускает setup
  },
],

Используется для однократного выполнения аутентификации перед всеми тестами с сохранением auth-состояния.

reporter

Формат вывода результатов тестов:

reporter: [
  ['html'],                                 // HTML-отчёт в playwright-report/
  ['junit', { outputFile: 'results.xml' }], // JUnit XML для CI
  ['list'],                                  // вывод в консоль в реальном времени
],

Для локальной разработки 'html' отлично подходит: открываешь playwright-report/index.html и получаешь полный визуальный отчёт. В CI добавляй 'junit': GitHub Actions, GitLab CI и Jenkins умеют его парсить.

globalSetup и globalTeardown

Для подготовки которая выполняется один раз перед всем сьютом:

globalSetup: './global-setup.ts',
globalTeardown: './global-teardown.ts',

// global-setup.ts
import { chromium } from '@playwright/test';

export default async function globalSetup() {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  
  // логинимся и сохраняем auth-состояние
  await page.goto('http://localhost:3000/login');
  await page.fill('[data-testid="email"]', 'admin@test.com');
  await page.fill('[data-testid="password"]', 'AdminPass1');
  await page.click('[data-testid="submit"]');
  await page.context().storageState({ path: 'auth.json' });
  
  await browser.close();
}

Тесты используют сохранённое auth-состояние без повторного входа:

use: {
  storageState: 'auth.json',
},

Готовый конфиг для продакшна

import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';

dotenv.config();

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  
  timeout: 45_000,
  expect: { timeout: 8_000 },
  
  reporter: [
    ['html'],
    ...(process.env.CI ? [['junit', { outputFile: 'test-results/results.xml' }] as const] : []),
  ],
  
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    video: 'retain-on-failure',
    screenshot: 'only-on-failure',
    actionTimeout: 10_000,
    navigationTimeout: 30_000,
  },
  
  projects: [
    {
      name: 'setup',
      testMatch: /auth\.setup\.ts/,
    },
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
    {
      name: 'api',
      testMatch: '**/api/**/*.spec.ts',
      use: { storageState: undefined },  // API-тестам не нужна браузерная авторизация
    },
  ],
});

Запуск конкретных проектов

# все тесты в chromium
npx playwright test --project=chromium

# только setup-проект
npx playwright test --project=setup

# несколько проектов
npx playwright test --project=chromium --project=firefox

Главные опции: шпаргалка

| Опция | Рекомендация |

|-------|--------------|

| testDir | './tests' |

| fullyParallel | true |

| forbidOnly | !!process.env.CI |

| retries | CI ? 2 : 0 |

| timeout | 30_000–60_000 |

| trace | 'on-first-retry' |

| video | 'retain-on-failure' |

| baseURL | из переменной окружения |

| reporter | HTML локально, + JUnit в CI |

→ See also: Установка Playwright: пошаговое руководство (2026) | Конфигурация окружений Playwright: локальная, стейджинг и продакшн | Параллельное выполнение в Playwright: workers, шарды и шардирование для ускорения | Переменные окружения в тестах Playwright: полное руководство