Playwright — это библиотека для автоматизации браузера на JavaScript/TypeScript: с её помощью тесты открывают страницу, кликают по кнопкам, заполняют формы и проверяют результат так же, как это делает живой пользователь, только без участия человека. За последние пару лет Playwright обогнал Selenium и Cypress по популярности в новых проектах — его чаще всего спрашивают на собеседованиях на позиции QA-automation в 2026 году.
Эта статья — пошаговый план для тех, кто начинает автотесты с нуля: что учить в каком порядке, примеры кода и где тренироваться бесплатно.
Эта статья — пошаговый план для тех, кто начинает автотесты с нуля: что учить в каком порядке, примеры кода и где тренироваться бесплатно.
Что нужно знать перед стартом
Playwright — не первый шаг в тестировании, а следующий. Прежде чем открывать документацию Playwright, стоит уверенно понимать ручное тестирование: что такое тест-кейс, чек-лист, баг-репорт, и разбираться в основах веба — HTTP, DevTools. Автотесты автоматизируют то, что вы уже умеете делать руками; они не заменяют понимание того, что и зачем вы проверяете.
Из языков программирования Playwright работает с JavaScript, TypeScript, Python, Java и C#, но самый частый стек в вакансиях 2026 года — JavaScript/TypeScript. Глубокое знание языка не требуется для старта: хватает переменных, функций, массивов, условий и async/await — именно эта база и нужна, чтобы читать и писать простые тесты.
Из языков программирования Playwright работает с JavaScript, TypeScript, Python, Java и C#, но самый частый стек в вакансиях 2026 года — JavaScript/TypeScript. Глубокое знание языка не требуется для старта: хватает переменных, функций, массивов, условий и async/await — именно эта база и нужна, чтобы читать и писать простые тесты.
Шаг 1. Основы JavaScript, без которых не пойдут тесты
Тесты в Playwright — это обычный JS/TS-код, поэтому нужен минимальный набор конструкций.
// переменные и типы
const url = 'https://example.com';
let counter = 0;
// функция
function isValidEmail(email) {
return email.includes('@');
}
// массив и перебор
const users = ['Анна', 'Борис', 'Вера'];
for (const user of users) {
console.log(user);
}
// условие
if (counter === 0) {
console.log('Счётчик пуст');
}
// переменные и типы
const url = 'https://example.com';
let counter = 0;
// функция
function isValidEmail(email) {
return email.includes('@');
}
// массив и перебор
const users = ['Анна', 'Борис', 'Вера'];
for (const user of users) {
console.log(user);
}
// условие
if (counter === 0) {
console.log('Счётчик пуст');
}
Отдельно стоит освоить async/await — почти все действия в Playwright асинхронны (открыть страницу, дождаться элемента, кликнуть), и без понимания асинхронности тесты будут падать непредсказуемо.
// async/await: дожидаемся результата асинхронной операции
async function loadUser(id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
}
// async/await: дожидаемся результата асинхронной операции
async function loadUser(id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
}
Шаг 2. Архитектура теста Playwright: test, describe, хуки
Любой тест в Playwright строится из нескольких повторяющихся блоков.
import { test, expect } from '@playwright/test';
test.describe('Авторизация', () => {
test('успешный вход с верными данными', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Пароль').fill('password123');
await page.getByRole('button', { name: 'Войти' }).click();
await expect(page).toHaveURL('/dashboard');
});
});
import { test, expect } from '@playwright/test';
test.describe('Авторизация', () => {
test('успешный вход с верными данными', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Пароль').fill('password123');
await page.getByRole('button', { name: 'Войти' }).click();
await expect(page).toHaveURL('/dashboard');
});
});
— `test()` — один тест-кейс. Первый аргумент — название, второй — асинхронная функция с логикой.
— `test.describe()` — группа связанных тестов, помогает организовать файл по функциональности.
— `{ page }` — объект страницы браузера, который Playwright передаёт в каждый тест автоматически. Через него происходят все действия.
Часто нужно повторить одни и те же шаги перед каждым тестом — например, залогиниться. Для этого есть хук beforeEach:
test.describe('Личный кабинет', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Пароль').fill('password123');
await page.getByRole('button', { name: 'Войти' }).click();
});
test('отображается имя пользователя', async ({ page }) => {
await expect(page.getByText('Анна')).toBeVisible();
});
test('доступна кнопка выхода', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Выйти' })).toBeVisible();
});
});
— `test.describe()` — группа связанных тестов, помогает организовать файл по функциональности.
— `{ page }` — объект страницы браузера, который Playwright передаёт в каждый тест автоматически. Через него происходят все действия.
Часто нужно повторить одни и те же шаги перед каждым тестом — например, залогиниться. Для этого есть хук beforeEach:
test.describe('Личный кабинет', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Пароль').fill('password123');
await page.getByRole('button', { name: 'Войти' }).click();
});
test('отображается имя пользователя', async ({ page }) => {
await expect(page.getByText('Анна')).toBeVisible();
});
test('доступна кнопка выхода', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Выйти' })).toBeVisible();
});
});
beforeEach выполняется перед каждым тестом в группе — не нужно копировать одни и те же шаги авторизации в каждый тест-кейс.
Конфиг и baseURL
Чтобы не писать полный адрес в каждом тесте, используется конфигурационный файл playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://staging.example.com',
headless: true,
},
});
Конфиг и baseURL
Чтобы не писать полный адрес в каждом тесте, используется конфигурационный файл playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://staging.example.com',
headless: true,
},
});
После этого page.goto('/login') в тестах автоматически подставляет baseURL и превращается в https://staging.example.com/login. Это удобно, когда тесты нужно гонять на разных окружениях (staging, prod) — меняется только конфиг, а не сами тесты.
Шаг 3. Локаторы и первые проверки
Локатор — это то, как тест находит элемент на странице. У Playwright есть набор специальных методов, и все они начинаются с getBy.
// по роли элемента (кнопка, ссылка, поле ввода) — рекомендуемый способ
page.getByRole('button', { name: 'Отправить' });
page.getByRole('link', { name: 'На главную' });
// по видимому тексту
page.getByText('Товар добавлен в корзину');
// по подписи поля формы
page.getByLabel('Email');
// по placeholder
page.getByPlaceholder('Введите email');
// по data-атрибуту (когда нет удобного текста/роли)
page.getByTestId('submit-button');
// по роли элемента (кнопка, ссылка, поле ввода) — рекомендуемый способ
page.getByRole('button', { name: 'Отправить' });
page.getByRole('link', { name: 'На главную' });
// по видимому тексту
page.getByText('Товар добавлен в корзину');
// по подписи поля формы
page.getByLabel('Email');
// по placeholder
page.getByPlaceholder('Введите email');
// по data-атрибуту (когда нет удобного текста/роли)
page.getByTestId('submit-button');
getByRole считается предпочтительным способом поиска элементов — он опирается на то, что реально видит и с чем взаимодействует пользователь (роль, доступное имя), а не на хрупкую структуру HTML или CSS-классы, которые часто меняются при рефакторинге вёрстки.
Дальше — действия и проверки:
test('добавление товара в корзину', async ({ page }) => {
await page.goto('/catalog');
// взаимодействие
await page.getByRole('button', { name: 'В корзину' }).first().click();
await page.getByLabel('Согласен с условиями').check();
// проверка (assertion)
await expect(page.getByText('Товар добавлен')).toBeVisible();
await expect(page.getByTestId('cart-count')).toHaveText('1');
});
Дальше — действия и проверки:
test('добавление товара в корзину', async ({ page }) => {
await page.goto('/catalog');
// взаимодействие
await page.getByRole('button', { name: 'В корзину' }).first().click();
await page.getByLabel('Согласен с условиями').check();
// проверка (assertion)
await expect(page.getByText('Товар добавлен')).toBeVisible();
await expect(page.getByTestId('cart-count')).toHaveText('1');
});
fill() вводит текст, click() кликает, check() отмечает чекбокс. expect(...).toBeVisible(), toHaveText(), toHaveURL() — самые частые проверки: элемент виден, текст совпадает, адрес страницы правильный.
Важная особенность Playwright — встроенные ожидания (auto-waiting). Перед кликом или проверкой он сам ждёт, пока элемент появится и станет доступен для взаимодействия, в пределах таймаута. Это снимает большую часть проблем с «мигающими» (flaky) тестами, которые были классической болью в старых инструментах вроде Selenium, — там ожидания приходилось прописывать вручную почти на каждый шаг.
Важная особенность Playwright — встроенные ожидания (auto-waiting). Перед кликом или проверкой он сам ждёт, пока элемент появится и станет доступен для взаимодействия, в пределах таймаута. Это снимает большую часть проблем с «мигающими» (flaky) тестами, которые были классической болью в старых инструментах вроде Selenium, — там ожидания приходилось прописывать вручную почти на каждый шаг.
Частые вопросы про Playwright на собеседовании
В чём разница между Playwright и Selenium? Playwright изначально проектировался под современный веб: у него встроенные ожидания элементов (auto-waiting), более быстрый и стабильный движок, официальная поддержка нескольких браузеров из коробки и удобный тест-раннер со встроенными отчётами. Selenium — более старый и универсальный инструмент с широкой экосистемой, но требует больше ручной настройки ожиданий и стабильности тестов.
Нужно ли знать TypeScript, чтобы писать тесты на Playwright? Необязательно — Playwright прекрасно работает и на обычном JavaScript. Но TypeScript в вакансиях 2026 года встречается чаще, потому что типизация ловит часть ошибок ещё до запуска тестов. Если только начинаете — стартуйте на JS, TypeScript добавляется как надстройка над теми же концепциями.
Чем `getByRole` лучше, чем поиск по CSS-селектору? getByRole находит элемент так, как его видит пользователь — по роли (кнопка, поле, ссылка) и доступному имени. CSS-селекторы и XPath завязаны на структуру разметки, которая часто меняется при правках вёрстки, — из-за этого такие локаторы чаще ломаются и требуют переписывания.
Что такое flaky-тесты и как Playwright с ними борется? Flaky (нестабильный) тест — тот, что иногда падает, иногда проходит на одном и том же коде, обычно из-за гонки между действием теста и скоростью отрисовки страницы. Playwright борется с этим встроенными ожиданиями: он не кликает по элементу, пока тот не станет видимым и стабильным, и не проверяет текст, пока страница не обновится.
С чего начать изучение Playwright новичку? С основ JavaScript (переменные, функции, async/await), затем — структура теста (test, describe, хуки), затем — локаторы и простые проверки. Дальше эти три темы нужно закрепить практикой на реальных задачах, а не только чтением документации.
Нужно ли знать TypeScript, чтобы писать тесты на Playwright? Необязательно — Playwright прекрасно работает и на обычном JavaScript. Но TypeScript в вакансиях 2026 года встречается чаще, потому что типизация ловит часть ошибок ещё до запуска тестов. Если только начинаете — стартуйте на JS, TypeScript добавляется как надстройка над теми же концепциями.
Чем `getByRole` лучше, чем поиск по CSS-селектору? getByRole находит элемент так, как его видит пользователь — по роли (кнопка, поле, ссылка) и доступному имени. CSS-селекторы и XPath завязаны на структуру разметки, которая часто меняется при правках вёрстки, — из-за этого такие локаторы чаще ломаются и требуют переписывания.
Что такое flaky-тесты и как Playwright с ними борется? Flaky (нестабильный) тест — тот, что иногда падает, иногда проходит на одном и том же коде, обычно из-за гонки между действием теста и скоростью отрисовки страницы. Playwright борется с этим встроенными ожиданиями: он не кликает по элементу, пока тот не станет видимым и стабильным, и не проверяет текст, пока страница не обновится.
С чего начать изучение Playwright новичку? С основ JavaScript (переменные, функции, async/await), затем — структура теста (test, describe, хуки), затем — локаторы и простые проверки. Дальше эти три темы нужно закрепить практикой на реальных задачах, а не только чтением документации.
Где практиковаться бесплатно
Теорию можно прочитать за вечер, а вот навык появляется только от практики — когда сам написал локатор, увидел, что тест падает, и разобрался почему. Ровно под эти три шага (JS-основы → архитектура Playwright → первые тесты) в Quality Academy сделали бесплатный тренажёр Playwright Arena — 30 задач в трёх модулях, без ограничения по количеству попыток и без оплаты. Условия задач и структура один в один повторяют план из этой статьи, только в виде практики с проверкой решения.
За прохождение модулей — бонусы: скидка на полноценный курс автотестирования после первого модуля и именной сертификат после второго. Если тренажёр закончится и захочется двигаться дальше — в школе есть полноценный курс «Автотестирование JS/TS + Playwright» с ментором, собственным проектом и разбором домашних заданий.
За прохождение модулей — бонусы: скидка на полноценный курс автотестирования после первого модуля и именной сертификат после второго. Если тренажёр закончится и захочется двигаться дальше — в школе есть полноценный курс «Автотестирование JS/TS + Playwright» с ментором, собственным проектом и разбором домашних заданий.
Итог
Playwright с нуля — это три последовательных навыка: базовый JavaScript с async/await, структура теста (test/describe/хуки/конфиг) и локаторы с проверками через getByRole и expect. Порядок имеет значение — пытаться сразу писать сложные тесты без понимания асинхронности почти всегда заканчивается непонятными падениями. Начните с простого теста на одну страницу, разберитесь, почему он иногда падает, и только потом переходите к более сложным сценариям.
-------
Полезные ссылки школы
Сайт Quality Academy:
https://quality-academy.ru/main
Telegram-канал:
https://t.me/quality_academy
YouTube-канал:
https://www.youtube.com/@quality_academy
ВКонтакте:
https://vk.com/quality_academy
Канал отзывов учеников (58+ отзывов):
https://t.me/quality_academy_reviews
Задать вопрос менеджеру:
https://t.me/quality_academy_bot
Тест «Подойдёт ли вам тестирование»:
https://quiz.quality-academy.ru
5000+ вопросов с собесов тестировщика — бот-тренажёр:
https://t.me/quality_academy_interview_bot
3 практические задачи и дорожная карта:
https://t.me/quality_academy_tasks_bot
Бесплатные тренажёры — SQL Arena, Playwright Arena, Python Arena:
SQL Arena · Playwright Arena · Python Arena
https://quality-academy.ru/main
Telegram-канал:
https://t.me/quality_academy
YouTube-канал:
https://www.youtube.com/@quality_academy
ВКонтакте:
https://vk.com/quality_academy
Канал отзывов учеников (58+ отзывов):
https://t.me/quality_academy_reviews
Задать вопрос менеджеру:
https://t.me/quality_academy_bot
Тест «Подойдёт ли вам тестирование»:
https://quiz.quality-academy.ru
5000+ вопросов с собесов тестировщика — бот-тренажёр:
https://t.me/quality_academy_interview_bot
3 практические задачи и дорожная карта:
https://t.me/quality_academy_tasks_bot
Бесплатные тренажёры — SQL Arena, Playwright Arena, Python Arena:
SQL Arena · Playwright Arena · Python Arena