# Playwright

## Що це таке

Playwright — фреймворк з відкритим кодом від Microsoft для автоматизації браузерів з єдиним
програмним інтерфейсом для Chromium, Firefox і WebKit. Playwright Test, опублікований у npm як
`@playwright/test`, — це тестовий раннер, побудований на ньому, і саме його найчастіше мають на
увазі, коли вживають цю назву. Той самий проєкт випускає звичайну бібліотеку для скриптів, які не є
тестами, інструмент командного рядка й MCP-сервер для ШІ-агентів, а також розширення для Visual
Studio Code, усе за ліцензією Apache License 2.0.

Окрім JavaScript і TypeScript, те саме керування браузером доступне з Python, де проєкт радить свій
плагін для pytest, з Java разом із будь-яким тестовим фреймворком, як-от JUnit, і з .NET з базовими
класами для MSTest, NUnit і xUnit.

`npx playwright install` завантажує власні збірки трьох рушіїв, і оскільки кожен реліз оновлює ці
версії, після оновлення команду може знадобитися запустити знову. Playwright також може керувати
Google Chrome і Microsoft Edge, якщо вони вже встановлені на машині. За замовчуванням тести
виконуються в режимі headless, без видимого вікна, і паралельно в усіх трьох рушіях. Кожен тест
отримує свіжий контекст браузера, рівнозначний новому профілю, тож cookie та сховище одного тесту не
переходять до наступного.

Тест читається як кроки, які зробила б людина:

```js
import { test, expect } from "@playwright/test";

test("після входу відкриваються вхідні", async ({ page }) => {
    await page.goto("https://example.com/sign-in");
    await page.getByLabel("Email").fill("reader@example.com");
    await page.getByRole("button", { name: "Увійти" }).click();
    await expect(page.getByRole("heading", { name: "Вхідні" })).toBeVisible();
});
```

Більшу частину роботи виконують два механізми. Перед дією Playwright робить перевірки готовності
елемента (actionability) і чекає, доки всі вони пройдуть. Для кліку локатор має вказувати рівно на
один елемент, а сам елемент має бути видимим, стабільним, тобто мати ту саму обмежувальну рамку
щонайменше два кадри анімації поспіль, здатним отримати клік, а не лежати під іншим елементом, і
активним. Якщо перевірки не проходять за відведений час, дія завершується помилкою `TimeoutError`.
Твердження (assertions) у формі `await expect(locator)` поводяться так само: вони знову й знову
отримують елемент, доки умова не справдиться або не мине тайм-аут твердження, за замовчуванням п'ять
секунд.

## Чому це важливо

Рішення, якому служить Playwright, стосується того, яку поведінку треба перевіряти в справжньому
браузері і як зробити ці перевірки настільки надійними, щоб червоній збірці вірили. Деякі вади
існують лише тоді, коли сторінку вже зібрано: діалог, що закриває кнопку, яку мав показати, макет,
що ховає поле на певній ширині, скрипт, що працює в одному рушії й падає з помилкою в іншому. Тести,
які запускають шматки коду окремо, їх не бачать.

Браузерні тести стають нестабільними (flaky), коли тест і сторінка змагаються наввипередки. Сторінка
завантажує дані, анімується й перемальовується, а тест, що клікає тієї миті, коли виконується його
рядок, іноді клікає зарано. Давнім засобом була фіксована пауза: закоротка на повільній машині й
марна трата часу на швидкій. Автоматичне очікування та твердження, що повторюють перевірку,
замінюють паузу умовою, від якої тест насправді залежить. Посібник про твердження каже прямо:
вебсторінки показують інформацію асинхронно, і твердження, які перевіряють лише раз, можуть зробити
тест нестабільним.

Другий вибір — як тест знаходить елементи. Посібник про локатори радить насамперед атрибути, які
бачить користувач, а понад усе локатори за роллю, бо `getByRole` з доступним ім'ям найближче до
того, як сторінку сприймають люди й допоміжні технології. Це має корисний побічний ефект: тест, що
натискає кнопку з назвою «Увійти», зламається, якщо кнопка втратить назву, а це та сама вада, на яку
натрапить людина з екранним читачем. Посібник також каже, що локатори за роллю не замінюють аудитів
доступності й тестів на відповідність. Ідентифікатори для тестів — запасний варіант. Посібник
називає їх найстійкішим способом і водночас таким, якого не бачать користувачі, тож набір, що
знаходить усе за id, доводить менше про те, що відчувають відвідувачі. CSS- і XPath-селектори не
рекомендовані, бо DOM часто змінюється.

Ціна — час. Запуск браузера й завантаження сторінки роблять браузерні тести найповільнішим видом
тестів у проєкті. Коли такий тест ламається на сервері збірки, повернутися до нього допомагає trace
viewer. Конфігурація за замовчуванням записує трасу під час першого повторного запуску тесту, що
впав, з двома повторами на CI й жодним локально, а траса проводить через кожну дію зі сторінкою до і
після неї, мережевими запитами й консоллю.

## Як це виглядає на практиці

Одна платформа тут тримає бізнес-логіку в базі даних, і роботою було
[побудувати багаторівневий набір тестів на чотирьох рівнях](/uk/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/).
Завданням було перевіряти поведінку кожного рівня там, де вона насправді живе, «а не перевіряти все
ззовні через браузер». В API на Go — 981 тестова функція. У базі даних — 494 файли поведінкових
тестів, тож збережену функцію тестують у самій базі даних, а не крізь три рівні застосунку над нею.
У фронтенді — 543 специфікації Vitest і Playwright, зокрема 48 файлів наскрізних тестів і 30
браузерних специфікацій; сторінка дає одне спільне число для обох інструментів і не ділить його.
Увесь набір запускається як 10 задач у workflow на 612 рядків, і сторінка прямо називає ціну: набір
повільний, кожна зміна сплачує йому свою данину, а за такого розміру він і сам потребує догляду.

Цей сайт керує власними браузерними перевірками за допомогою іншої бібліотеки, Puppeteer, і
[сторінка подяк](/uk/credits/) показує той самий компроміс. Ці перевірки охоплюють те, чого
валідатор зробити не може, наприклад вимірювання контрасту, порядок фокуса, розмір цілі, вихід за
межі вікна й розбиття на сторінки під час друку. Вони тривають близько двадцяти хвилин, тому
запускаються на вимогу, а не з кожним комітом: швидку половину беруть на себе обов'язкові перевірки,
а повільну запускає людина.

## Де виникають проблеми

Більшість проблем із Playwright походить від тестів, які перевіряють менше, ніж обіцяють їхні назви.

**Фіксована пауза підміняє умову.** Тест чекає дві секунди й потім читає сторінку або один раз читає
значення й порівнює його звичайним твердженням. На завантаженому сервері збірки двох секунд іноді
замало. Перевіряйте те, що побачили б відвідувачі, твердженням, яке повторює перевірку, наприклад
`toHaveText`.

**Елементи шукають за розміткою.** Селектор крізь три вкладені елементи `div` або клас оформлення
ламається з наступним редизайном, хоча сторінка й далі працює. Шукайте елемент за роллю й доступним
ім'ям або за підписом чи текстом, а ідентифікатор для тестів додавайте лише там, де елемент
неможливо впізнати за тим, що сприймають користувачі.

**Успішний локатор за роллю вважають перевіркою доступності.** `getByRole` доводить, що один елемент
має ту роль і те ім'я, які задав тест. Про контраст, порядок фокуса чи решту сторінки він не каже
нічого. Для цього запускайте з тесту рушій правил, наприклад axe, як це робить власний
[посібник](https://playwright.dev/docs/accessibility-testing) Playwright через
`@axe-core/playwright`; сканування охоплює сторінку в тому стані, у якому вона є на момент виклику,
тож спершу відкрийте меню чи діалог.

**Клік проштовхують силоміць.** Параметр `force` вимикає неістотні перевірки готовності; для кліку
Playwright перестає перевіряти, чи ціль справді отримує подію. Тест, якому він потрібен, часто
обходить те, на що натрапили б і відвідувачі, наприклад банер над кнопкою. Сприймайте початкову
помилку як знахідку: або закрийте банер так, як це зробили б відвідувачі, або виправте перекриття.

**Нестабільний тест перезапускають, доки він не пройде.** Коли повтори ввімкнено, тест, що впав під
час першого запуску й пройшов під час повтору, позначається як flaky, а не як невдалий. Тест, який
лишається нестабільним тиждень у тиждень, або змагається зі сторінкою, або ловить справжню ваду, що
то з'являється, то зникає, і траса, записана під час його першого повтору, — місце, з якого варто
почати.

**Усе перевіряють через браузер.** Правило про ціни чи права доступу, перевірене кліками крізь три
екрани, працює повільно й ламається з причин, які до правила не мають стосунку. Перевіряйте правило
там, де воно живе, а браузерні тести залиште для того, що може показати лише браузер: шлях
користувача, макет і відмінності між рушіями.

## Що почитати далі

- [Installation](https://playwright.dev/docs/intro) — встановлення Playwright Test, запуск прикладів
  тестів, HTML-звіт і UI Mode.
- [Locators](https://playwright.dev/docs/locators) — рекомендований порядок пошуку елементів, від
  ролі й підпису до ідентифікаторів для тестів.
- [Auto-waiting](https://playwright.dev/docs/actionability) — перевірки готовності перед кожною дією
  і що саме вимикає `force`.
- [Assertions](https://playwright.dev/docs/test-assertions) — твердження з повторною перевіркою і
  без неї, тайм-аут за замовчуванням, м'які твердження й опитування.
- [Trace viewer](https://playwright.dev/docs/trace-viewer-intro) — запис траси під час повтору й
  покроковий перегляд тесту, що впав.
- [Browsers](https://playwright.dev/docs/browsers) — встановлення рушіїв, запуск Chrome і Edge та
  два режими headless.

<https://engineer.company/uk/glossary/playwright/>
