Розділ 1 з 12
Раннер і бібліотека: що таке Playwright Test
Playwright існує у двох формах. Бібліотека playwright вміє керувати браузером. Пакет @playwright/test додає до неї повноцінний тестовий фреймворк: раннер, assertions, ізоляцію, паралельність і інструменти для налагодження.
Документація описує Playwright Test як end-to-end фреймворк для сучасних вебзастосунків, в який уже вбудовано test runner, assertions, ізоляцію, паралелізацію та інструменти. Він працює з Chromium, WebKit і Firefox на Windows, Linux і macOS, локально й у CI, у headless- або headed-режимі, з емуляцією мобільних Chrome для Android і Mobile Safari.
Щоб відчути різницю, порівняйте той самий сценарій у двох формах. У бібліотеці ви самі запускаєте браузер, створюєте контекст і сторінку, закриваєте все у finally і пишете перевірки вручну. У раннері ці обов'язки бере на себе інфраструктура: ви оголошуєте, що вам потрібна page, і отримуєте готову сторінку в новому ізольованому контексті.
Коли потрібна бібліотека, а коли раннер
Проблема. Новачки інколи пишуть тести як скрипти: вручну запускають chromium.launch() і перевіряють результат через if.
Чому це погано. Такий скрипт не має ізоляції між тестами, звітів, повторів, паралельного запуску й assertions з автоочікуванням. Усе це доведеться будувати самому, і це буде гірше, ніж у раннері.
Рішення. Для тестування беріть @playwright/test і вбудовані фікстури (page, context, request).
Коли бібліотека доречна. Для автоматизації, що не є тестами: скрипт, який робить скриншоти, заповнює форму чи збирає дані.
Розділ 2 з 12
Встановлення і структура проєкту
Одна команда створює проєкт з конфігом, прикладом тесту і завантаженими браузерами. Важливо розуміти, навіщо потрібен кожен файл і що з'явиться після першого запуску.
Системні вимоги
Станом на Playwright 1.63 документація вимагає Node.js останньої версії гілок 22.x, 24.x або 26.x. Операційні системи: Windows 11+, Windows Server 2019+ або WSL; macOS 14 (Sonoma) і новіші; Debian 12 і 13, Ubuntu 22.04, 24.04 і 26.04 (x86-64 або arm64). Перевірити, яка версія Node.js стоїть у вас, можна командою node -v.
Ініціалізація
Команда нижче або створює новий проєкт, або додає Playwright до наявного. Під час запуску вона ставить кілька питань: TypeScript чи JavaScript (за замовчуванням TypeScript), назва каталогу для тестів (за замовчуванням tests, а якщо такий уже є, то e2e), чи додавати GitHub Actions workflow і чи завантажувати браузери (за замовчуванням так). Повторний запуск команди наявних тестів не перезаписує.
Перший запуск і звіт
За замовчуванням тести з шаблону запускаються без вікна браузера (headless) і паралельно у Chromium, Firefox і WebKit. Результат видно в терміналі, а HTML-звіт відкривається автоматично лише тоді, коли щось упало. Відкрити його вручну можна окремою командою.
Оновлення
Версія браузерів прив'язана до версії Playwright, тому після оновлення пакета браузери теж треба перевстановити. Прапорець --with-deps додатково ставить системні залежності браузерів.
Для VS Code є офіційне розширення Playwright Test. Воно показує тести в боковій панелі, запускає й налагоджує окремі тести та вміє записувати нові через codegen.
Розділ 3 з 12
playwright.config.ts
Конфіг збирає в одному місці все, що стосується запуску: де шукати тести, скільки воркерів, скільки повторів, які звіти, у яких браузерах і з якими налаштуваннями сторінки.
Функція defineConfig нічого не змінює в значеннях: вона потрібна для типізації, тож редактор підказує назви опцій і лає за неіснуючі. У конфігу три рівні. Верхній рівень керує самим раннером: пошуком тестів, воркерами, повторами, звітами. Блок use задає параметри фікстур і браузера, тобто те, якою буде page в кожному тесті. Масив projects дозволяє запустити ті самі тести кілька разів з різними налаштуваннями, наприклад у трьох браузерах.
Де живе slowMo
Проблема. У старих прикладах уповільнення задають через ручний chromium.launch({ slowMo: 500 }) у тесті або пишуть use: { slowMo: 500 }.
Чому. slowMo — це параметр запуску браузера, а не опція фікстури. Ручний launch() обходить фікстуру browser і всю ізоляцію раннера, а use.slowMo не існує, тож tsc на ньому впаде.
Рішення. Параметри запуску браузера передаються через use.launchOptions: launchOptions: { slowMo: 500 }.
Коли. Лише для демонстрації чи налагодження. У звичайних прогонах тримайте 0, бо уповільнення множиться на кожну дію.
Опції, задані в конфігу, можна перевизначити на рівні проєкту (projects[].use), файлу чи групи тестів (test.use({ ... })), а для одного запуску — прапорцями командного рядка, наприклад --workers, --retries чи --timeout.
Розділ 4 з 12
Запуск і налагодження
Команда npx playwright test має десятки прапорців. Найактуальніший список завжди дає npx playwright test --help, а на практиці щодня потрібні з десяток.
Позиційні аргументи після test — це фільтри файлів. Кожен трактується як регулярний вираз і порівнюється з абсолютним шляхом до файлу, тож npx playwright test cart запустить усі файли, у шляху яких є «cart». Суфікс :42 звужує запуск до тесту на конкретному рядку. Прапорець -g (--grep) фільтрує вже за назвою тесту, а -G (--grep-invert) виключає тести за назвою.
Три режими налагодження
UI mode (--ui) — основне робоче середовище під час написання тестів. Це вікно зі списком тестів, режимом спостереження, покроковим переглядом дій і «подорожжю в часі» по DOM-знімках кожного кроку.
Прапорець --debug відкриває Playwright Inspector і дозволяє йти по тесту крок за кроком. Довідка CLI уточнює, що це скорочення для змінної PWDEBUG=1 разом з опціями --timeout=0 --max-failures=1 --headed --workers=1. Тобто тайм-аут вимикається, браузер видно, працює один воркер і прогін зупиняється на першому падінні. Для одного тесту зручно поєднати з номером рядка: npx playwright test cart.spec.ts:42 --debug.
Розширення VS Code дає те саме прямо в редакторі: точки зупинки, запуск окремого тесту кліком і підсвічування локаторів.
Корисні прапорці для CI і рефакторингу. --last-failed перезапускає лише тести, що впали минулого разу. --only-changed запускає тести з файлів, змінених відносно Git-ревізії (без аргументу — незакомічені зміни). --repeat-each=10 ганяє кожен тест десять разів і допомагає ловити нестабільність. --list лише показує, які тести буде зібрано, нічого не запускаючи.
Розділ 5 з 12
Браузери і projects
Project — це іменований набір налаштувань, з яким раннер проганяє тести. Найчастіше projects відповідають браузерам, але так само можна розділити середовища, ролі користувачів чи десктоп і мобільну версію.
Playwright завантажує власні збірки Chromium, Firefox і WebKit, сумісні з конкретною версією пакета. Об'єкт devices містить готові профілі пристроїв: розмір вікна, user agent, масштаб, підтримку дотиків і браузерний рушій. Коли ви пишете { ...devices['Desktop Safari'] }, тести цього проєкту йдуть у WebKit із десктопними параметрами.
Окрім збірок Playwright, можна запускати тести у встановлених «брендових» браузерах через опцію channel: 'chrome' або 'msedge'. Це корисно, коли треба перевірити саме той Chrome чи Edge, яким користуються клієнти.
Залежності між projects
Project може залежати від іншого через поле dependencies. Типовий приклад — setup-проєкт, який один раз логіниться і зберігає стан сесії, а основні проєкти стартують лише після нього. Документація радить цей підхід як сучасну альтернативу globalSetup: setup-кроки відображаються у звіті, мають трейси і можуть використовувати фікстури. Прапорець --no-deps дозволяє запустити проєкт без його залежностей.
Детально авторизацію й збереження сесії розберемо в окремій темі, тут важливо лише розуміти механіку: dependencies задає порядок запуску projects.
Розділ 6 з 12
Паралелізм, воркери і шардинг
Раннер запускає тести в кількох воркерах — окремих процесах Node.js, у кожного свій браузер. Від того, як тести розподіляються між воркерами, залежать і швидкість прогону, і те, які тести можуть заважати один одному.
Кількість воркерів задає опція workers або прапорець -j/--workers. Значення може бути числом або відсотком логічних ядер процесора. За замовчуванням воркерів стільки, скільки половина логічних ядер. Шаблон npm init playwright ставить у CI workers: 1, щоб не перевантажувати слабкі CI-машини. Це рішення шаблону, а не обмеження раннера.
Без додаткових налаштувань паралельно виконуються файли, а тести всередині одного файлу йдуть по черзі в тому самому воркері. Опція fullyParallel: true дозволяє розподіляти по воркерах кожен тест окремо. Для окремого файлу чи групи режим можна змінити через test.describe.configure({ mode }). Режим 'parallel' запускає тести групи паралельно. Режим 'default' повертає послідовне виконання, і це корисно, щоб перекрити fullyParallel з конфігу. Режим 'serial' робить тести залежними: якщо один падає, наступні пропускаються, а повтор стартує з початку групи.
Чому serial — останній варіант
Проблема. Тести в одному файлі передають дані один одному через змінні: перший створює замовлення, другий його перевіряє.
Чому. Такі тести ламаються з fullyParallel, бо можуть потрапити в різні воркери, а у воркерів немає спільної пам'яті. Режим serial маскує проблему, і документація прямо каже, що послідовний запуск не рекомендований: краще робити тести ізольованими.
Рішення. Кожен тест сам готує потрібний стан: через API-запит, фікстуру чи beforeEach.
Коли serial виправданий. Коли сценарій справді є одним довгим потоком, який неможливо розбити, і ви свідомо погоджуєтеся на повільніший і крихкіший запуск.
Ізоляція і перезапуск воркера
Кожен тест отримує новий BrowserContext, тож cookies, localStorage і сесії між тестами не протікають навіть у межах одного воркера. Якщо тест падає, раннер перезапускає воркер-процес, щоб наступні тести стартували з чистого середовища. Для кожного воркера доступні testInfo.workerIndex і testInfo.parallelIndex: їх використовують, наприклад, щоб кожен воркер працював зі своїм тестовим користувачем.
Шардинг
Коли однієї машини замало, набір тестів ділять на шарди й запускають на кількох машинах CI одночасно. Прапорець --shard=1/3 означає «виконати першу з трьох частин». Щоб отримати один спільний звіт, кожен шард пише звіт у форматі blob, а потім їх зливає команда npx playwright merge-reports.
Розділ 7 з 12
Анатомія тесту: фікстури, describe, step і хуки
Тест — це функція, яку раннер викликає з об'єктом фікстур. Ви деструктуруєте з нього лише те, що потрібно, і раннер створює саме ці ресурси, а після тесту прибирає їх.
Функція тесту асинхронна, і кожна дія Playwright повертає Promise, тож перед кожною дією та web-first assertion стоїть await. test.describe групує тести: хуки й test.use всередині групи діють лише на неї, а назва групи стає частиною повної назви тесту у звіті. test.step ділить тест на іменовані кроки, які видно у звіті, UI mode і трейсі. Крок може повертати значення: const id = await test.step('create', async () => ...).
Вбудовані фікстури та їхній scope
Фікстури бувають двох масштабів. Test-scoped фікстура створюється заново для кожного тесту. Worker-scoped створюється один раз на воркер і живе, доки живе процес. page, context і request — test-scoped: у кожного тесту свої. browser і browserName — worker-scoped: браузер один на воркер, а ізоляцію забезпечує новий контекст для кожного тесту. Перевірте себе.
Хуки
beforeEach і afterEach виконуються навколо кожного тесту й мають доступ до тих самих фікстур, що й тест. beforeAll і afterAll виконуються один раз на воркер для файлу чи групи. Документація підкреслює дві речі. Хук beforeAll отримує лише worker-фікстури, тому page у ньому недоступна. А оскільки воркер перезапускається після падіння тесту, beforeAll у новому воркері виконається знову. Отже, «один раз на весь прогін» він не гарантує.
Розділ 8 з 12
Анотації, теги і фільтрація
Анотації змінюють, як раннер поводиться з тестом: пропустити, чекати падіння, дати більше часу. Теги нічого не змінюють у виконанні, але дозволяють вибирати групи тестів під час запуску.
test.skip() пропускає тест, часто за умовою. test.fixme() позначає тест, який треба полагодити: раннер одразу його перериває і не виконує. test.fail() каже, що тест має падати: Playwright запускає його і перевіряє, що він справді падає, а якщо тест раптом проходить, раннер про це повідомить. Це зручно для задокументованого відомого бага. test.slow() потроює тайм-аут тесту. test.only() запускає лише позначені тести і призначений тільки для локальної роботи. Щоб він не потрапив у CI, у конфігу є forbidOnly.
Теги
Тег задається в деталях тесту через поле tag або прямо в назві. Кожен тег має починатися з @. Теги видно у звіті, а фільтрують за ними через --grep і --grep-invert або через опцію grep у конфігу чи проєкті.
Розділ 9 з 12
Assertions, тайм-аути і retries
Три механізми, від яких залежить стабільність тестів: assertions, що самі повторюють перевірку, тайм-аути, які обмежують очікування, і повтори, що відрізняють нестабільний тест від зламаного.
Auto-retrying проти non-retrying
Асинхронні matchers для Locator, Page і APIResponse — toBeVisible, toHaveText, toHaveURL, toHaveCount та інші — повторюють перевірку, доки умова не виконається або не мине expect.timeout (за замовчуванням 5 секунд). Перед ними обов'язково ставиться await. Звичайні matchers на кшталт toBe, toEqual, toContain чи toBeTruthy перевіряють значення один раз, у ту мить, коли їх викликано.
expect.configure({ timeout: 10_000 }) створює окремий екземпляр expect зі своїми налаштуваннями, наприклад для повільної частини застосунку, не змінюючи глобальний тайм-аут.
Тайм-аути
Тайм-аутів кілька, і вони вкладені. Весь тест, разом із фікстурами і beforeEach/afterEach, обмежений тайм-аутом тесту: 30 секунд за замовчуванням. Кожен web-first assertion має свій тайм-аут 5 секунд. У дій (click, fill) і навігації (goto) власного тайм-ауту за замовчуванням немає: значення 0 означає «без ліміту», тож їх обмежує лише тайм-аут тесту. Загальний ліміт на весь прогін (globalTimeout) за замовчуванням вимкнений.
toPass не бере expect.timeout
Проблема. Здається, що expect(...).toPass() повторює блок 5 секунд, як і інші assertions.
Чому це не так. За замовчуванням тайм-аут toPass дорівнює 0, і документація окремо наголошує, що він не враховує власний expect.timeout. Без явного значення блок повторюватиметься, доки не вичерпається тайм-аут усього тесту.
Рішення. Завжди передавайте тайм-аут: toPass({ timeout: 15_000 }).
Коли. У кожному toPass, де ви не хочете віддати йому весь бюджет тесту.
Retries і flaky-тести
Опція retries (або прапорець --retries) дозволяє перезапустити тест, що впав. Шаблон ставить 2 повтори в CI і 0 локально. Тест, який спершу впав, а на повторі пройшов, отримує статус flaky. Він не валить прогін, але сигналізує про нестабільність, яку треба розслідувати. Прапорець --fail-on-flaky-tests робить прогін червоним, якщо знайдено хоч один flaky-тест. Повтори поєднуються з trace: 'on-first-retry': трейс записується саме тоді, коли він найбільше потрібен.
Розділ 10 з 12
Звіти і трейси
Звіт відповідає на питання «що впало», а трейс — «чому». Раннер уміє одночасно писати кілька звітів і сам вирішує, для яких запусків зберігати трейси, скриншоти й відео.
Якщо репортер не задано, раннер використовує list, а в CI — dot. Шаблон npm init playwright одразу ставить 'html'. Вбудовані репортери в Playwright 1.63: list, line і dot для терміналу, html для інтерактивного звіту, json і junit для інтеграцій, github для анотацій у GitHub Actions, blob для злиття звітів шардів, perfetto і null. Кілька репортерів задаються масивом.
Трейси, скриншоти, відео
Трейс — це запис прогону: кожна дія зі знімками DOM до й після, мережа, консоль і вихідний код. Його відкривають у Trace Viewer (npx playwright show-trace path/to/trace.zip) або прямо з HTML-звіту. За замовчуванням трейс вимкнено. Режим у use.trace вирішує дві речі: коли трейс записувати і коли зберігати.
Для скриншотів (use.screenshot) доступні режими 'off', 'on', 'only-on-failure' і 'on-first-failure'. Для відео (use.video) логіка режимів подібна до трейсів, наприклад 'retain-on-failure' чи 'on-first-retry'. Усі артефакти потрапляють у test-results/ і прикріплюються до тесту в HTML-звіті.
Розділ 11 з 12
Типові помилки
Помилки з цього списку не завжди червоні одразу. Частина з них робить тести повільними, частина — нестабільними, частина проявляється лише в CI.
Найчастіші помилки такі. Забутий test.only, коли в конфігу немає forbidOnly. Пропущений await перед web-first assertion. page у beforeAll. Тести, що передають дані через спільні змінні. Ручне читання стану замість auto-retrying matcher. toPass без тайм-ауту. Плутанина між тайм-аутом тесту і тайм-аутом assertion. І slowMo не в тому місці конфігу. Нижче кожна з них у вигляді коду: знайдіть проблемний рядок.
Розділ 12 з 12
Шпаргалка
Усе основне на одному екрані. Після шпаргалки — підсумковий квіз для самоперевірки.
Три правила на пам'ять. Тести ізольовані: кожен готує свій стан і не залежить від порядку. Перевірки робляться через auto-retrying assertions з await, а не через ручне читання стану. Налаштування живуть у конфігу на правильному рівні: раннер нагорі, браузер і фікстури в use, варіанти запуску в projects.
Самоперевірка
Підсумковий квіз
15 питань за всіма розділами. Після кожної відповіді побачите пояснення, а в кінці — список тем, які варто повторити.