Что такое Playwright?

Playwright — современный фреймворк автоматизации браузеров от Microsoft. Он предоставляет единый API для управления браузерами Chromium, Firefox и WebKit. Выпущенный в 2020 году, быстро стал самым популярным выбором для новых проектов автоматизации.

Почему Playwright?

ВозможностьPlaywrightSelenium
Auto-waitingВстроенныйРучные ожидания
МультибраузерностьChromium, Firefox, WebKitОтдельные драйверы
СкоростьОчень высокаяСредняя
ЛокаторыПо роли, тексту, test-idCSS, XPath, ID
ОтладкаTrace Viewer, InspectorТолько скриншоты
API-тестированиеВстроенноеОтдельный инструмент
CodegenВстроенныйНедоступен
Параллельное выполнениеНативноеТребует Grid

Настройка Playwright

JavaScript/TypeScript

npm init playwright@latest

Python

pip install playwright
playwright install

Написание первого теста

import { test, expect } from '@playwright/test';

test('пользователь может войти и увидеть дашборд', async ({ page }) => {
  await page.goto('https://app.example.com/login');
  await page.fill('[data-testid="email"]', 'admin@test.com');
  await page.fill('[data-testid="password"]', 'secret123');
  await page.click('[data-testid="submit"]');

  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('.welcome')).toHaveText('Welcome, Admin');
});

test('невалидный логин показывает ошибку', async ({ page }) => {
  await page.goto('https://app.example.com/login');
  await page.fill('[data-testid="email"]', 'wrong@test.com');
  await page.fill('[data-testid="password"]', 'wrongpass');
  await page.click('[data-testid="submit"]');

  await expect(page.locator('.error')).toHaveText('Неверные учётные данные');
});

Мощные локаторы

Локаторы по роли (Рекомендуется)

await page.getByRole('button', { name: 'Войти' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('admin@test.com');
await page.getByLabel('Email').fill('admin@test.com');
await page.getByPlaceholder('Введите email').fill('admin@test.com');
await page.getByText('Войти').click();
await page.getByTestId('login-submit').click();

Цепочки и фильтрация локаторов

await page.locator('.product-card').filter({ hasText: 'Беспроводная мышь' })
  .getByRole('button', { name: 'В корзину' }).click();

await page.locator('.product-card').nth(0).click();
await page.locator('.product-card').first().click();

Auto-Waiting

// Ручные ожидания не нужны — Playwright справляется сам
await page.click('#submit');
// Playwright ждёт: видимость, стабильность, активность, приём событий

await expect(page.locator('.result')).toHaveText('Успех');
// Playwright повторяет попытки до прохождения ассерта (в пределах таймаута)

Web-First ассерты

await expect(page).toHaveTitle('Dashboard');
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('.status')).toHaveText('Активен');
await expect(page.locator('.item')).toHaveCount(5);
await expect(page.locator('#btn')).toBeVisible();
await expect(page.locator('#btn')).toBeEnabled();
await expect(page.locator('#input')).toHaveValue('hello');

Конфигурация

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

export default defineConfig({
  testDir: './tests',
  timeout: 30000,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: [['html'], ['junit', { outputFile: 'results.xml' }]],

  use: {
    baseURL: 'https://app.example.com',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
  },

  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 5'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
  ],
});

Продвинутые возможности

Trace Viewer

npx playwright test
npx playwright show-trace trace.zip

Trace показывает: скриншоты на каждом шаге, снимки DOM, сетевые запросы, логи консоли и исходный код.

Codegen — Запись тестов

npx playwright codegen https://app.example.com

Codegen открывает браузер и записывает ваши действия, генерируя тест-код в реальном времени.

API-тестирование (Встроенное)

test('создать пользователя через API', async ({ request }) => {
  const response = await request.post('/api/users', {
    data: { name: 'Test User', email: 'test@example.com' },
  });
  expect(response.ok()).toBeTruthy();
  const user = await response.json();
  expect(user.name).toBe('Test User');
});

test('админ создаёт пользователя через API, проверяет в UI', async ({ page, request }) => {
  const response = await request.post('/api/users', {
    data: { name: 'Новый пользователь', email: 'new@test.com' }
  });
  const user = await response.json();
  await page.goto(`/admin/users/${user.id}`);
  await expect(page.locator('.user-name')).toHaveText('Новый пользователь');
});

Перехват сетевых запросов

await page.route('/api/users', route => {
  route.fulfill({
    status: 200,
    body: JSON.stringify([{ id: 1, name: 'Mock User' }]),
  });
});

const [response] = await Promise.all([
  page.waitForResponse('/api/checkout'),
  page.click('#pay-button'),
]);
expect(response.status()).toBe(200);

Множественные контексты браузера

test('два пользователя взаимодействуют в реальном времени', async ({ browser }) => {
  const adminContext = await browser.newContext();
  const userContext = await browser.newContext();
  const adminPage = await adminContext.newPage();
  const userPage = await userContext.newPage();

  await adminPage.goto('/admin/chat');
  await adminPage.fill('#message', 'Привет пользователь!');
  await adminPage.click('#send');

  await userPage.goto('/chat');
  await expect(userPage.locator('.message')).toHaveText('Привет пользователь!');

  await adminContext.close();
  await userContext.close();
});

Запуск тестов

npx playwright test                           # Все тесты
npx playwright test tests/login.spec.ts       # Конкретный файл
npx playwright test --project=firefox         # Конкретный браузер
npx playwright test --headed                  # С интерфейсом
npx playwright test --ui                      # Интерактивный режим
npx playwright test --debug tests/login.spec.ts  # Отладка
npx playwright show-report                    # HTML-отчёт

Упражнение: Постройте suite тестов на Playwright

Создайте полный набор тестов Playwright:

  1. Инициализируйте проект с TypeScript
  2. Настройте 3 браузерных проекта (Chrome, Firefox, WebKit)
  3. Создайте Page Objects для Login, Dashboard и Settings
  4. Напишите 8 тестов: логин (валидный/невалидный), навигация, форма, API + UI, мок сети, мульти-viewport, сравнение скриншотов
  5. Настройте traces и скриншоты при падении
  6. Запустите тесты параллельно во всех браузерах
  7. Сгенерируйте и просмотрите HTML-отчёт

Ключевые выводы

  • Auto-waiting Playwright устраняет большинство нестабильных тестов из-за проблем с таймингом
  • Локаторы по роли — самая устойчивая стратегия поиска элементов
  • Trace Viewer предоставляет непревзойдённые возможности отладки
  • Встроенное API-тестирование позволяет смешивать быструю API-подготовку с UI-проверкой
  • Codegen записывает взаимодействия с браузером и генерирует тест-код
  • Нативное параллельное выполнение в Chromium, Firefox и WebKit
  • Фикстуры Playwright естественно интегрируются с Page Object Model