Перейти к основному содержимому

Playwright

Тестировщику Разработчику

Зачем эта статья. Selenium — классика с долгой историей. Playwright (Microsoft) чаще выбирают для новых веб-проектов: стабильные ожидания, три движка браузера, встроенные скриншоты и trace. Здесь — путь от нуля до первого автотеста в CI с пояснением терминов для новичка.

Что такое E2E-автоматизация

E2E (end-to-end) — тест проходит весь путь пользователя в реальном браузере: открыть сайт → войти → оформить заказ → увидеть подтверждение.

УровеньЧто проверяетИнструмент (примеры)
UnitОдна функция/классpytest, JUnit
APIHTTP без UIPostman, REST-клиент в коде
E2EUI + браузер + сетьPlaywright, Selenium

E2E медленнее и хрупче (ломается при смене вёрстки), зато ловит ошибки интеграции, которые unit не видит. Обычно их меньше, чем unit, но на критичных сценариях (оплата, регистрация) они обязательны.

Ручная проверка того же сценария — Ручное тестирование веба. Общая теория автоматизации — 115.


Selenium или Playwright?

:::info Сравнение

SeleniumPlaywright
Возраст экосистемыОчень зрелая, много legacyМоложе, активно растёт
Ожидания элементовЧасто пишут вручнуюAuto-wait по умолчанию
БраузерыЧерез отдельные драйверыChromium, Firefox, WebKit из коробки
ОтладкаЛоги + скрины самиTrace Viewer, video, screenshot on fail
Когда братьEnterprise, старый стек, Appium-опытНовый фронт, React/Vue, CI на GitHub Actions

Обе технологии валидны. Для обучения начните с Playwright на зелёном проекте; Selenium — если команда уже на нём сидит. :::

Словарь

ТерминЗначение
HeadlessБраузер без окна — быстрее в CI
HeadedС видимым окном — удобно при отладке
ЛокаторСпособ найти элемент на странице
Flaky-тестИногда падает без изменений кода — часто тайминги
FixtureПодготовка окружения (браузер, авторизация)
Page ObjectКласс страницы со своими кнопками и полями

Установка

Нужны Node.js 18+ (или Python/Java — Playwright мультиязычен; ниже — TypeScript как самый частый выбор в E2E).

npm init playwright@latest

Мастер спросит: папку тестов (tests), базовый URL, установку браузеров. После установки:

npx playwright test
npx playwright test --ui

--uiUI Mode: пошаговый прогон, удобно QA без глубокого опыта в коде.

Структура проекта (типично):

project/
playwright.config.ts # настройки
tests/
example.spec.ts # тесты
package.json

Первый тест — построчно

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

test('главная страница открывается', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle(/Example Domain/);
});
СтрокаЧто происходит
test(...)Один сценарий с именем для отчёта
async ({ page })Playwright даёт вкладку браузера page
gotoПереход по URL, ожидание загрузки
expect(...).toHaveTitleПроверка заголовка; ретраи до таймаута — без sleep

Структура E2E как в автоматизации: подготовка → действие → проверка (assert).

Несколько тестов в файле

test.describe('Каталог', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/catalog');
});

test('список товаров виден', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'Каталог' })).toBeVisible();
});
});

beforeEach — общая подготовка перед каждым тестом в группе.


Локаторы — как не ловить flaky-тесты

Flaky — тест упал на CI, локально прошёл. Частая причина — элемент ещё не появился или изменился селектор.

Приоритет локаторов (от устойчивых к хрупким):

ПриоритетЛокаторПример
1getByRolepage.getByRole('button', { name: 'Войти' })
2getByLabelpage.getByLabel('Email')
3getByTestIdpage.getByTestId('checkout-submit')
4getByTextосторожно при смене языка
5CSS/XPathтолько если иначе никак

Попросите разработчиков добавить data-testid на критичные элементы — договорённость команды.

await page.getByTestId('login-email').fill('qa@test.local');
await page.getByTestId('login-password').fill('Secret123!');
await page.getByRole('button', { name: 'Войти' }).click();
await expect(page.getByText('Личный кабинет')).toBeVisible();

Auto-wait и assertions

Playwright перед кликом ждёт, пока элемент visible, stable, enabled. Ошибка Selenium «element not interactable» встречается реже.

await expect(page.locator('.toast-success')).toHaveText('Заказ оформлен');
await expect(page).toHaveURL(/\/orders\/\d+/);

Проверка API в том же тесте

const responsePromise = page.waitForResponse('**/api/orders');
await page.getByRole('button', { name: 'Оформить' }).click();
const response = await responsePromise;
expect(response.status()).toBe(201);

Так вы связываете UI и проверку API в одном сценарии.


Авторизация без повторного логина

Долгий логин в каждом тесте замедляет прогон. Паттерн storageState:

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

setup('authenticate', async ({ page }) => {
await page.goto('/login');
await page.getByTestId('login-email').fill('qa@test.local');
await page.getByTestId('login-password').fill('Secret123!');
await page.getByRole('button', { name: 'Войти' }).click();
await page.context().storageState({ path: 'playwright/.auth/user.json' });
});

В playwright.config.ts укажите storageState: 'playwright/.auth/user.json' для проектов, которым нужна сессия. Один раз залогинились — остальные тесты стартуют уже авторизованными.


Page Object (кратко)

Когда тестов больше пяти, выносите страницы в классы — как в автоматизации:

// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test';

export class LoginPage {
readonly email: Locator;
readonly password: Locator;
readonly submit: Locator;

constructor(private page: Page) {
this.email = page.getByTestId('login-email');
this.password = page.getByTestId('login-password');
this.submit = page.getByRole('button', { name: 'Войти' });
}

async login(email: string, password: string) {
await this.email.fill(email);
await this.password.fill(password);
await this.submit.click();
}
}

В тесте: const login = new LoginPage(page); await login.login(...). Вёрстка поменялась — правите один файл.


playwright.config.ts — что трогать чаще всего

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

export default defineConfig({
testDir: './tests',
timeout: 30_000,
use: {
baseURL: 'https://test.shop.example',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
],
});
ОпцияСмысл
baseURLКороткие goto('/catalog') вместо полного URL
timeoutМаксимум на один тест
traceЗапись шагов при падении / ретрае
projectsПрогон в нескольких браузерах

Отладка падений

После падения:

npx playwright show-trace trace.zip

Trace Viewer — шаги, DOM, сеть; аналог «записи сессии» для разбора бага.

Дополнительно:

npx playwright test --debug
npx playwright codegen https://test.shop.example

codegen — запись действий в код (стартовая заготовка, потом рефакторинг локаторов).


CI (GitHub Actions)

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/

Отчёт HTML — артефакт для команды QA. При падении скачайте trace и report из CI.


Типичные ошибки новичка

ОшибкаРешение
sleep(5000) вездеexpect с auto-wait
XPath на полный DOMgetByRole / getByTestId
Один огромный тест на 200 строкtest.describe + Page Object
Тесты зависят от порядкаИзолировать данные, уникальный email
Гоняют только локально headless=falseПериодически прогон как в CI

Практика в этом разделе

ШагМатериал
Ручная проверка UIРучное тестирование веба
Практикум E2E1013 — пользовательский сценарий
Каталог инструментов118 — UI и E2E
Данные после сценарияSQL для тестировщика

Куда дальше


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).