07 · Інструменти автоматизації
Playwright: архітектура, браузери і контексти
Зміст
«А в Safari перевіряли?» — найчастіше на це відповідають «так, у конфігу є проєкт webkit». Відповідь неточна, і неточність тут не термінологічна: інструмент водить власну патчену збірку WebKit, а з брендовим Safari не працює взагалі. Те саме з рештою обіцянок: «прогнали headless, як у CI», «новий контекст — це ж новий браузер, дорого», «тести чистять за собою, ізоляція є». Кожна з цих фраз або правдива, або хибна залежно від того, як інструмент улаштований — і саме архітектура визначає, що ти справді перевірив.
Тому глава не про синтаксис. Вона про три речі, які потім щодня повертаються в роботі: чим Playwright дістається до браузера (і чому в ньому немає окремих драйверів), які саме браузери він запускає, і що таке (browser context) — рівень, на якому тримається вся ізоляція тестів. Різниця між «клікав за туторіалом» і «розуміє інструмент» видна вже на питанні «навіщо контекст, якщо є браузер».
Власний протокол і CDP: чому немає окремих драйверів
Інструменти автоматизації різняться не набором команд, а тим, як тестовий код дістається до браузера. (browser control model) три, і канон їхнього порівняння — глава Ландшафт інструментів. Тут потрібне лише те, що з них випливає для Playwright.
Модель перша — wire-протокол поза процесом браузера. Специфікація W3C описує WebDriver як інтерфейс дистанційного керування з платформо- і мовно-нейтральним wire-протоколом для програм, що працюють поза процесом браузера; призначення назване прямо — дати авторам писати тести, що автоматизують браузер з окремого керувального процесу. Ланцюг вузлів у специфікації теж названий поіменно: local end (мовна бібліотека поверх протоколу), intermediary node (, який реалізує обидва боки — сюди лягає Selenium Grid на кілька машин) і endpoint node, реалізований самим браузером. Ключова вимога: будь-який віддалений вузол мусить бути невідрізнимим як чорна скринька з погляду клієнта — саме тому той самий тест іде і на локальний драйвер, і на віддалену ферму без правок. Selenium — «парасольковий проєкт» (umbrella project) із трьох частин, у ядрі якого WebDriver як інтерфейс, а кросбраузерність тримається на стандарті W3C, не на власному протоколі.
Модель друга — власний протокол інструмента. Тут бібліотека дає єдину API для запуску браузерів і взаємодії з ними, а (test runner) додає до неї повністю керований наскрізний прогін. Окремих драйверів під кожен браузер немає, бо браузери ставить сама команда інструмента, а системні залежності можуть доставитися автоматично — підбирати драйвер під версію браузера не треба взагалі. Ціна прямо протилежна перевазі: браузери свої. За замовчуванням це відкрита збірка Chromium, а не Google Chrome; з брендовими Firefox і Safari інструмент не працює, бо покладається на патчі власних збірок; брендові Chrome і Edge доступні окремими каналами — тобто «справжній браузер» тут вибір, а не дефолт.
Модель третя — виконання всередині браузера. Cypress називає це постійним компромісом, а не тимчасовим обмеженням: команди виконуються всередині браузера, тож немає серіалізації обʼєктів і wire-протоколів і є прямий доступ до застосунку. Зворотний бік того самого — тестовий код виконується в браузері, не в Node, мовою лишається JavaScript, серверні бібліотеки не імпортуються, а двома браузерами одночасно ця модель не керує.
А де тут CDP? Протокол DevTools (Chrome DevTools Protocol, CDP) — не четверта модель, а конкретний протокол усередині другої, і найкраще це видно з боку надбудов. Дока CodeceptJS описує свої бекенди через спосіб керування: WebDriver — «Native browser automation via WebDriver Protocol», Puppeteer — «Chromium automation via DevTools Protocol», Playwright — автоматизація Chromium, Firefox і WebKit. Тобто протокол DevTools у самому формулюванні привʼязаний до Chromium — і звідси прямий наслідок (це вже наш вивід, а не цитата): інструмент, який обіцяє три різні браузери, не може стояти лише на ньому. Заодно та сама дока дає найкорисніше застереження про надбудови: «однакова API» не означає взаємозамінності, і контрприклад наведений самим джерелом — заголовки запиту ставляться в Playwright і Puppeteer, а у WebDriver ні.
// codecept.conf.js — хелпер вирішує, ЧИМ водити браузер, сценарії не змінюються
helpers: {
Playwright: { url: 'http://localhost:3000' }
}
Ієрархія: browser → context → page
Найкраще цю ієрархію видно там, де її ніхто за тебе не збирає — у бібліотеці. Дока перелічує кроки дослівно: обрати тип браузера, запустити браузер, створити контекст, створити сторінку. Закриття контексту й браузера — теж твій обовʼязок.
import { chromium } from 'playwright';
const browser = await chromium.launch(); // процес браузера
const context = await browser.newContext(); // ізольований профіль
const page = await context.newPage(); // сторінка в цьому профілі
await page.goto('https://example.com');
await context.close();
await browser.close(); // прибрати за собою — руками
Ранер робить те саме, але сам: ізольовані page і context приходять у тест як вбудовані (fixture), створюються ліниво (лише якщо тест назвав їх у своїх аргументах) і закриваються без твоєї участі.
import { test, expect } from '@playwright/test';
test('кошик нового користувача порожній', async ({ page }) => {
await page.goto('/cart');
await expect(page.getByText('Кошик порожній')).toBeVisible();
});
Три рівні означають три різні речі. browser — процес браузера: запустити його дорого, тому запускають рідко. context — проміжний рівень між процесом і сторінкою: власний профіль зі своїми кукі та сховищем. page — сторінка всередині цього профілю, і саме з нею працюють навігація, й дії.
Різниця бібліотеки й ранера не косметична, і на це варто дивитися ще до першого падіння. Web-first assertions — перевірки, що самі чекають і перезапускаються, доки умова не виконається, — властивість ранера, не бібліотеки. Модель теж різна: бібліотека дає 30 секунд на більшість операцій, а в ранері таймаут стоїть на тесті (за замовчуванням теж 30 секунд), і більшість операцій власного таймауту не має. Ще одна причина брати ранер — матриця конфігурацій: щоб прогнати той самий сценарій на іншому браузері чи пристрої, бібліотека вимагає правити скрипт, а ранер описує матрицю в одному місці й сам множить прогін на неї. Детально це — глави про перевірки й автоочікування та фікстури й конфігурацію.
Контекст як дешева ізоляція
Ізоляція тесту — це не гасло, а перелік: власні localStorage, sessionStorage й кукі в кожного тесту. Тести Playwright виконуються в ізольованих середовищах з чистого аркуша, і ця модель названа причиною відтворюваності й захисту від каскадних падінь. Механізм — контексти, еквівалентні інкогніто-профілям: вони швидкі й дешеві у створенні й повністю ізольовані, навіть коли працюють в одному браузері. Ось відповідь на «навіщо контекст, якщо є браузер»: ізоляція профілю без вартості запуску процесу. Кожен тест дістає свіжий контекст — новий профіль браузера з майже нульовими накладними витратами; під ранером контекст на тест створюється за замовчуванням.
Вигоди дока називає три, і всі три — практичні: падіння одного тесту не переноситься на інший; дебажити легше, бо один тест можна прогнати скільки завгодно разів; не треба думати про порядок у паралельному прогоні й . Останнє важливіше, ніж здається: без ізоляції паралельність і шардінг перестають бути безпечними — порядок виконання вже не той, під який тести писалися, тож зазвичай саме там і вилазить протікання стану; деталі в главі Паралельний запуск.
Тут же лежить розвилка, на якій ламаються цілі . Стратегій ізоляції дві — почати з нуля або прибирати між тестами, — і дока аргументує проти другої: про легко забути, а дещо (наприклад, «відвідані посилання») прибрати неможливо. Стан із одного тесту протікає в наступний, і падає вже не той тест, у якому проблема. Класика тестових патернів каже те саме мовою причин: взаємозалежні тести зазвичай спричинені спільною фікстурою, де один тест залежить від результату іншого; маркер саме цієї причини діагностичний — тест сам по собі зелений, а в сюїті падає, коли до неї додають або з неї прибирають інший тест. Лікування назване прямо: свіжа фікстура на кожен тест запобігає нестабільним тестам. Канон незалежності тестів як принципу — глава Анатомія автотесту; тут — його механізм в інструменті.
Дешевий контекст дає ще одну штатну можливість: кілька контекстів в одному сценарії. Це не хак, а задокументований спосіб перевірити багатокористувацьку функціональність — на кшталт чату. Дві ролі в одному тесті — це два контексти з різними станами.
// два незалежні профілі в одному тесті: у кожного свої кукі й сховище
const sellerContext = await browser.newContext();
const buyerContext = await browser.newContext();
const seller = await sellerContext.newPage();
const buyer = await buyerContext.newPage();
Логічне продовження — не логінитися в кожному тесті заново, а завантажувати готовий стан: це тема глави Автентифікація і повторне використання стану. Що саме браузер тримає в кукі й сховищі — у главі Кукі, сесії та сховище браузера.
Свої браузери: що саме ти перевіряєш
Інструмент водить три браузери — Chromium, WebKit і Firefox — плюс брендові Google Chrome і Microsoft Edge; емуляція планшетів і мобільних — окремий режим, а не окремий браузер. Слово «брендові» тут несе основне навантаження.
Chromium на версію попереду
Для Chrome, Edge та інших браузерів на Chromium за замовчуванням беруться відкриті збірки Chromium. Проєкт Chromium іде поперед брендових браузерів, тому коли світ на Google Chrome N, інструмент уже підтримує Chromium N+1, який доїде в Chrome і Edge за кілька тижнів. Це не деталь інсталяції: ти тестуєш на збірці, яка в користувача зʼявиться пізніше.
Firefox і WebKit — патчені збірки
Версія Firefox відповідає свіжій стабільній, але з брендовим Firefox інструмент не працює, бо покладається на патчі. WebKit береться з останніх джерел головної гілки — часто ще до того, як ці зміни увійдуть у Apple Safari, — і з брендовим Safari інструмент так само не працює; замість цього тестують на найсвіжішій збірці WebKit. Практичний висновок неприємний, але його краще знати до релізу: «перевірили в Safari» через цей інструмент означає «перевірили у власній збірці WebKit».
Мало того, той самий на різних ОС поводиться по-різному. Причина, яку називає дока, загальна — можливості, що сильно залежать від платформи, — а приклад наведений поіменно: доступні медіакодеки істотно різняться між Linux, macOS і Windows. WebKit на Linux-CI — зазвичай найдешевший варіант, але для досвіду, найближчого до Safari, WebKit треба ганяти на mac — наприклад, якщо в застосунку є відтворення відео.
Headless — інша збірка, а не прапорець
Тут найчастіша хиба інтуїції. Інструмент постачає звичайну збірку Chromium для видимих (headed) прогонів і окремий бінарник chromium headless shell для headless. Тобто «те саме, тільки без вікна» — не про цей випадок: це різні збірки. Додатковий шар: брендові Chrome і Edge перейшли на нову реалізацію headless-режиму, ближчу до звичайного видимого режиму, і вона відрізняється від chromium headless shell, який інструмент використовує за замовчуванням, — дока прямо просить очікувати різну поведінку.
Звідси наслідок, який економить години: «локально headed зелене, у CI headless червоне» може бути різницею збірок, а не логіки застосунку чи тесту. Перше, що варто зробити з таким падінням, — прогнати локально в тому самому режимі, що в CI, а не переписувати локатор. Інструментарій розбору падінь — глава Дебаг, trace viewer і репортинг; чутливість -порівняння до режиму рендерингу — глава Візуальне тестування.
Що з цього виходить для матриці браузерів
Знання, що збірки свої, змінює не код, а домовленості. Канон кросбраузерності — глава Кросбраузерність і адаптивна верстка; тут — три речі, які прямо чіпляються за архітектуру інструмента.
По-перше, мета не в піксельній ідентичності. Сайт не мусить давати однаковий досвід у всіх браузерах, доки базова функціональність доступна якимось способом. Тож «у WebKit тінь на два пікселі інша» — здебільшого не дефект, а різниця .
По-друге, покрити геть усі браузери й пристрої практично неможливо, тому діапазон підтримки — домовленість із власником продукту, і будується вона з даних про аудиторію, а не з уподобань команди. Готовий мінімальний кістяк дає базовий набір Baseline: Chrome (десктоп і Android), Edge, Firefox (десктоп і Android), Safari (macOS та iOS). Практичний наслідок для матриці: браузери на спільному рушії рендерингу не потребують окремих рядків для більшості перевірок верстки — Chrome, Edge й Opera тут ідуть разом.
По-третє, причин кросбраузерних дефектів три: вади й розбіжності реалізацій у самих браузерах; різний рівень підтримки можливостей; обмеження самого пристрою. Перша означає, що дефект може бути в браузері, а не у вашому застосунку — і тоді його заводять вендору. А звіт без платформи, пристрою й версії браузера непридатний: локалізація починається саме з цих даних.
Типові помилки
Виглядає як «прогнали в Safari», а насправді — прогнали у власній збірці WebKit: із брендовим Safari інструмент не працює, бо покладається на патчі. Формулювання в звіті має бути точним, інакше команда вважає закритим.
Виглядає як «новий контекст — це новий браузер, тому дорого», а насправді — контекст дешевий і швидкий у створенні й повністю ізольований навіть в одному браузері. Економити на контекстах, перевикористовуючи один на всю сюїту, означає платити протіканням стану замість економії секунд.
Виглядає як «ізоляція є, ми чистимо в afterEach», а насправді — це слабша з двох стратегій: про прибирання легко забути, а дещо (як «відвідані посилання») прибрати неможливо. Чистий старт сильніший саме тим, що при падінні дивитися треба лише в межах цього тесту.
Виглядає як , а насправді — взаємозалежні тести: маркер точний, тест сам по собі зелений, а падає, коли до сюїти додають або з неї прибирають інший тест. замаскують симптом, але спільної фікстури не приберуть.
Виглядає як «у CI падає, бо headless слабший», а насправді — headless тут окремий бінарник, а не той самий браузер із прапорцем, і нова реалізація headless-режиму в брендових браузерах поводиться інакше за нього. Це різниця збірок, а не «слабкість» режиму.
Виглядає як «WebKit у Linux-CI дорівнює Safari на mac», а насправді — доступні медіакодеки істотно різняться між ОС, тому для досвіду, найближчого до Safari, WebKit ганяють на mac.
Підсумок
- Драйверів немає, бо модель інша. Playwright ходить до браузера власним протоколом і сам ставить браузери й системні залежності; натомість платформо- і мовно-нейтральний
wire-протокол — властивість моделі W3C WebDriver, і саме з нього ростуть віддалене виконання й ланцюг вузлів із проксі посередині. - Ієрархія рівно триярусна:
browser— процес,context— ізольований профіль зі своїми кукі й сховищем,page— сторінка в цьому профілі. У бібліотеці ти будуєш і закриваєш це руками, у ранеріpageіcontextприходять фікстурами й закриваються самі. - Ізоляція живе в контексті, і вона дешева. Контекст еквівалентний інкогніто-профілю, повністю ізольований навіть в одному браузері й створюється на кожен тест за замовчуванням — тому чистий старт сильніший за прибирання між тестами.
- Браузери — свої, і це межа твоїх обіцянок. Chromium на версію попереду брендового, Firefox і WebKit — патчені збірки, з брендовими Firefox і Safari інструмент не працює, а той самий рушій браузера на різних ОС поводиться по-різному.
- Headless — інша збірка, а не . Тому «локально зелене, у CI червоне» треба спершу перевірити як різницю режимів і збірок, а вже потім як баг.
Можливі питання
- «Навіщо потрібен контекст, якщо вже є браузер?» Очікують точну відповідь, а не «для ізоляції»: контекст дає ізоляцію профілю без вартості запуску процесу — це інкогніто-профіль усередині вже запущеного браузера. Сильна відповідь додає перелік того, що ізолюється: кукі,
localStorage,sessionStorage. - «Як Playwright ізолює тести і чому це дешево?» Інтервʼюер перевіряє, чи ти знаєш, що свіжий контекст на кожен тест — дефолт ранера, а не твоя ручна робота. Плюс три названі наслідки: немає перенесення падіння, один тест можна прогнати скільки завгодно разів, не треба думати про порядок у паралелі й шардінгу.
- «Опиши ієрархію обʼєктів Playwright». Питання-фільтр:
browser → context → page. Тут же люблять доуточнити, хто що закриває — у бібліотеці контекст і браузер закриваєш ти, вбудовані фікстури ранера закриваються самі. - «Як перевірити сценарій із двома користувачами в одному тесті?» Правильний хід — два контексти з різними станами, а не два браузери й не логаут посередині тесту.
- «Ви ж тестуєте в Safari?» Пастка на точність. Сильний кандидат розводить брендовий Safari і збірку WebKit, згадує, що з брендовим Safari інструмент не працює, і що WebKit на Linux-CI не дорівнює WebKit на mac.
- «Тест зелений локально й червоний у CI — з чого почнеш?» Дивляться на порядок гіпотез, а не на список фіч. Архітектурна відповідь: спершу режим і збірка (headed проти окремого бінарника headless), потім ізоляція — чи тест падає сам по собі, бо це відрізняє взаємозалежні тести від усього іншого.
- «Чим Playwright відрізняється від Selenium і Cypress?» Питання про моделі керування браузером, а не про синтаксис; розбір — у главі Ландшафт інструментів.
Джерела
Власний протокол і CDP: чому немає окремих драйверів
- W3C — WebDriver Level 2 — означення WebDriver як дистанційного інтерфейсу з
wire-протоколом і ланцюг вузлів local end → intermediary node → endpoint node. - Selenium — Documentation (оглядова сторінка) — Selenium як із трьох частин; кросбраузерність тримається на стандарті W3C.
- Playwright — Library — розділення інструмента на бібліотеку (керує браузером) і ранер (додає керований наскрізний прогін).
- Playwright — Browsers — браузери й системні залежності ставить сама команда інструмента; збірки свої, брендові Chrome і Edge — окремі канали.
- Cypress — Trade-offs — модель «виконання в браузері»: без серіалізації й
wire-протоколу, але код у браузері й не два браузери водночас. - CodeceptJS — Basics — хелпери як бекенди трьох моделей, зокрема Puppeteer через DevTools-протокол, і застереження, що однакова API не означає взаємозамінності.
Ієрархія: browser → context → page
- Playwright — Library — дослівний перелік кроків
browser → context → page, ліниві вбудовані фікстури ранера, різниця моделей таймаутів і матриця конфігурацій. - Playwright — Test Isolation (browser contexts) — контекст як механізм ізоляції з власними кукі й сховищем, створений на кожен тест.
- Playwright — Browsers — які браузери водить інструмент і чим його збірки відрізняються від брендових.
- Playwright — Authentication — ізоляція контекстів як причина відтворюваності й захисту від каскадних падінь.
- Playwright — головна сторінка — свіжий контекст на кожен тест, рівносильний новому профілю браузера.
- Playwright — Test Isolation (browser contexts) — означення ізоляції тесту, контекст як інкогніто-профіль, три названі вигоди, дві стратегії ізоляції й кілька контекстів в одному сценарії.
- Playwright — Best Practices — вимога повної ізоляції тесту з власними сховищем і кукі.
- Playwright — головна сторінка — свіжий контекст на тест із майже нульовими накладними витратами.
- Playwright — Authentication — ізоляція як причина відтворюваності; дві ролі в одному тесті — два контексти з різними станами.
- Playwright — Library — ізольовані
pageіcontextяк вбудовані фікстури ранера. - Playwright — Browsers — межі того, у чому саме ця ізоляція відтворюється.
- xUnit Test Patterns — Erratic Test — спільна фікстура як причина взаємозалежних тестів і маркер «сам зелений, у сюїті падає».
- xUnit Test Patterns — Fresh Fixture — свіжа фікстура на кожен тест як засіб проти нестабільних тестів.
Свої браузери: що саме ти перевіряєш
- Playwright — Browsers — перелік водимих браузерів і каналів, збірки Chromium на версію попереду, патчені Firefox і WebKit, різниця платформ у медіакодеках, окремий бінарник
chromium headless shellі застереження про нову реалізацію headless-режиму. - Playwright — Library — вибір типу браузера як перший крок ініціалізації.
- Playwright — Test Isolation (browser contexts) — контекст як профіль усередині обраного браузера.
- Playwright — Authentication — межі відтворюваності, які дає ізоляція контекстів.
- Playwright — головна сторінка — один API на Chromium, Firefox і WebKit.
Що з цього виходить для матриці браузерів
- MDN — Introduction to cross-browser testing — мета не піксельна ідентичність, матриця як домовленість із власником продукту на даних про аудиторію, три причини кросбраузерних дефектів, вимоги до звіту про дефект.
- web.dev — Baseline (Web Platform Baseline) — базовий набір браузерів як мінімальний кістяк матриці.
- Playwright — Browsers — патчені збірки Firefox і WebKit, різниця медіакодеків між ОС, окремий бінарник headless shell і нова реалізація headless-режиму.
- Playwright — Test Isolation (browser contexts) — дешевизна контексту, повна ізоляція в одному браузері й аргументи проти прибирання між тестами.
- Playwright — Library — хто закриває контекст і браузер у бібліотеці, а хто в ранері.
- Playwright — Authentication — ізоляція як причина відтворюваності й захисту від каскадних падінь.
- Playwright — головна сторінка — свіжий контекст на тест як новий профіль браузера.
- Playwright — Best Practices — вимога повної ізоляції з власними сховищем і кукі.
- xUnit Test Patterns — Erratic Test — спільна фікстура як корінь взаємозалежних тестів і діагностичний маркер.
- xUnit Test Patterns — Fresh Fixture — свіжа фікстура на тест як усунення нестабільності.
- Playwright — Test Isolation (browser contexts) — контекст як інкогніто-профіль, склад ізольованого стану, три названі вигоди й кілька контекстів в одному сценарії.
- Playwright — Library — ієрархія
browser → context → pageі хто закриває рівні в бібліотеці проти ранера. - Playwright — головна сторінка — свіжий контекст на кожен тест, рівносильний новому профілю браузера.
- Playwright — Authentication — дві ролі в одному тесті як два контексти з різними станами.
- Playwright — Browsers — брендовий Safari проти збірки WebKit, різниця ОС і headless-збірки.
- Playwright — Best Practices — формулювання вимоги ізоляції, яке очікують почути.
- xUnit Test Patterns — Erratic Test — маркер «сам зелений, у сюїті падає» як перший крок .
- xUnit Test Patterns — Fresh Fixture — свіжа фікстура на тест як канонічне лікування нестабільності.
Відео до теми
Як тестовий код Playwright керує браузером і чому тут не потрібні окремі драйвери?
Playwright ходить до браузера власним протоколом інструмента, а не стандартом, який реалізує сам браузер. Бібліотека відповідає за запуск браузерів і взаємодію з ними одним API на всі три браузери, а тестовий добудовує до неї повністю керований наскрізний прогін. Окремий драйвер під кожен браузер тут просто зайвий: браузери й системні залежності постачає команда самого інструмента, тож підбирати драйвер під версію браузера не треба взагалі. Для контрасту варто згадати модель W3C WebDriver — платформо- і мовно-нейтральний wire-протокол для програм, які керують браузером поза його процесом; там ланцюг довший: мовна бібліотека (local end), за потреби (intermediary node) і браузер як endpoint node. Плата за відсутність драйверів прямо протилежна вигоді: браузери тут власні — дефолтом іде відкритий Chromium, а брендовий Google Chrome підключають окремим каналом. Тобто «поставилось однією командою» і «тестую не рівно те, що в користувача» — дві сторони одного архітектурного рішення.
Чим Playwright-бібліотека відрізняється від Playwright-ранера?
Бібліотека вміє лише водити браузер, ранер додає все, що робить із цього тестовий фреймворк. У бібліотеці ти сам обираєш тип браузера, стартуєш процес, створюєш контекст і сторінку — і сам їх закриваєш. Ранер віддає page і context вбудованими : вони створюються ліниво — тобто лише тоді, коли тест перелічив їх у своїх аргументах, — і прибираються без твоєї участі. Перевірки, які самі чекають і повторюють спробу, доки умова не виконається (web-first assertions), — властивість ранера, а не бібліотеки. Модель теж не спільна: у бібліотеці ліміт живе на операціях (типово 30 секунд), у ранері — на самому тесті (типово ті ж 30 секунд), і власного таймауту більшість операцій не має. Практичний наслідок: перенести той самий сценарій на інший браузер або пристрій у бібліотеці означає редагувати код, а ранер тримає матрицю конфігурацій в одному місці й множить прогін на неї сам.
Опиши ієрархію обʼєктів Playwright.
Рівнів рівно три: browser → context → page. browser — це процес браузера, і його запуск найдорожча операція, тому процес підіймають рідко. context — проміжний рівень між процесом і сторінкою, окремий профіль зі своїми кукі, localStorage і sessionStorage. page — сторінка всередині цього профілю, і саме на ній живуть навігація, та дії. Один процес спокійно тримає кілька контекстів, а один контекст — кілька сторінок (наприклад, попап, відкритий із першої). Питання зазвичай іде в парі з доуточненням, хто прибирає рівні: у бібліотеці закривати контекст і браузер — твій обовʼязок, у ранері вбудовані фікстури роблять це самі.
Навіщо потрібен контекст, якщо вже є браузер?
Бо контекст дає ізоляцію профілю без вартості запуску процесу. Відповідь «для ізоляції» тут вважають слабкою: важлива саме ця вилка — щоб отримати чисті кукі й сховище, не обовʼязково піднімати новий браузер. Контекст поводиться як інкогніто-профіль: створюється швидко й дешево, але ізольований повністю — навіть коли кілька контекстів працюють в одному процесі. Сильна відповідь одразу перелічує, що саме розʼїжджається по контекстах: кукі, localStorage, sessionStorage. Звідси й типова оптимізація навпаки: процес браузера перевикористовують, а контекст роблять свіжий на кожен тест.
Що дає ізоляцію тестів у Playwright і чи треба її вмикати руками?
Ізоляцію дає контекст, і під ранером вона дефолтна: свіжий контекст на кожен тест створюється за замовчуванням, це не твоя ручна робота. Технічно кожен тест стартує з чистого аркуша — власні кукі, localStorage і sessionStorage, — а вартість цього близька до нуля, бо процес браузера не перезапускається. Вигод із цього три, і перелічити їх варто списком: падіння одного тесту не тягне за собою решту; дебаг простіший, бо один і той самий тест можна прогнати скільки завгодно разів; порядок виконання перестає мати значення для паралельного прогону й . Останнє тримає всю паралельність: як тільки ізоляція протікає, порядок стає значущим, а він у паралельному прогоні вже не той, під який тести писалися. Тому «ізоляція» тут не гасло, а того, що прогін масштабується вширину.
Дві стратегії ізоляції — чистий старт і прибирання між тестами. Чому радять першу?
після тесту виглядає рівноцінним, але воно слабше з двох причин. Перша побутова: про крок прибирання легко забути, а забутий крок ніхто не підсвітить — тест лишиться зеленим і тихо занесе сміття в наступний. Друга принципова: частину стану прибрати неможливо, класичний приклад — уже відвідані посилання. Плюс сама діагностика гірша: коли стан протікає, падає не той тест, у якому проблема, і час іде на розбір здорового коду. Чистий старт дає інший гарантований інваріант — усе, що впливає на цей тест, створене в межах цього тесту, тож і дивитися треба лише сюди. Тому afterEach із чисткою — не заміна свіжому контексту, а щонайбільше додаток до нього для зовнішніх систем (даних у БД, створених сутностей).
Тест зелений сам по собі, але падає в повній сюїті. Який діагноз і що робити?
Це майже канонічний маркер взаємозалежних тестів: поодинці тест стабільно зелений, а червоніє тільки тоді, коли склад змінюють — додали або прибрали інший тест. Причина зазвичай одна — спільна фікстура, через яку один тест спирається на результат іншого (залогінений користувач, створена сутність, наповнене сховище). Лікування називається так само однозначно: свіжа фікстура на кожен тест прибирає саму передумову нестабільності, тобто свіжий контекст замість спільного і власні дані замість «того самого юзера». тут — маскування: вони поженуть тест удруге, а спільну фікстуру не приберуть, і симптом повернеться на іншому наборі. Перше практичне питання при такому падінні — «а він падає сам по собі?»: відповідь одразу відсікає взаємозалежність від усіх інших гіпотез.
Як перевірити сценарій із двома користувачами в межах одного тесту?
Двома контекстами в одному браузері — по контексту на роль, у кожної свій стан. Це не хак, а штатний спосіб перевіряти багатокористувацьку функціональність: чат, де двоє переписуються, продавець і покупець на маркетплейсі, погодження документа автором і рецензентом. Кожна роль дістає власний контекст, у ньому власну сторінку — і жодна не бачить кукі та сховище іншої. Два браузерні процеси тут не потрібні: процес дорогий, а ізоляцію дає рівнем нижче. Логаут посередині тесту — найгірший із варіантів: він робить сценарій послідовним (обидві ролі не існують одночасно), а тест — крихким на кожній зміні флоу автентифікації.
CDP — це те, чим Playwright водить усі три браузери?
Ні. Протокол DevTools (Chrome DevTools Protocol, CDP) — не окрема модель керування, а конкретний протокол усередині моделі «власний протокол інструмента», і він привʼязаний до Chromium — саме так його й описують: автоматизація Chromium через DevTools-протокол (це формулювання про Puppeteer). Звідси прямий висновок: інструмент, який обіцяє три різні браузери, не може стояти лише на CDP — інакше Firefox і WebKit просто не було б чим водити. Плутанина зазвичай іде з двох боків: або CDP називають «протоколом Playwright», або його ставлять поруч із WebDriver як четверту модель. У практичному житті різниця вилазить у CDP-специфічних можливостях: вони доступні тільки в Chromium, і сценарій, який на них спирається, у WebKit чи Firefox не поїде.
Чи означає однаковий фасад API, що бекенди керування взаємозамінні?
Ні, і найкраще це видно на надбудовах на кшталт CodeceptJS, де сценарій написаний однаково, а хелпер вирішує, чим водити браузер. Однакова API — це зручність міграції, не гарантія однакової поведінки: частина можливостей просто не існує в конкретній моделі керування. Класичний контрприклад із самої документації: заголовки запиту можна виставити через Playwright і Puppeteer, а через WebDriver ні. Тому обіцянка «перепишемо конфіг і поїдемо на іншому бекенді» на практиці означає ще й аудит того, які кроки сценаріїв спираються на можливості, яких у новій моделі немає. На співбесіді тут дивляться, чи кандидат розрізняє синтаксис і модель керування під ним.
«Ви ж тестуєте в Safari?» Як відповісти точно?
Точна відповідь розводить два різні обʼєкти: брендовий Apple Safari і збірку WebKit, яку запускає інструмент. Брендовий Safari цим інструментом не керується взагалі, бо той тримається на патчах власних збірок; WebKit він бере зі свіжих джерел головної гілки — нерідко раніше, ніж ці зміни доїдуть у релізний Safari. Тобто «проєкт webkit у конфігу зелений» коректно перекладається як «перевірено на свіжій збірці WebKit», а не «перевірено в Safari». Різниця не термінологічна: якщо в звіті стоїть «Safari OK», команда вважає закритим, хоча брендовий браузер ніхто не запускав. З брендовим Firefox ситуація та сама, а от Chrome і Edge доступні окремими каналами — саме тому «справжній браузер» тут усвідомлений вибір, а не дефолт.
Яку версію Chromium запускає Playwright і чому це варто знати?
Для Chrome, Edge та решти браузерів на Chromium інструмент за замовчуванням бере відкриті збірки самого Chromium. А Chromium як проєкт випереджає брендові браузери: коли в користувачів Chrome версії N, підтримуваний інструментом Chromium уже N+1 — у брендові браузери ці зміни доїдуть за кілька тижнів. Це не деталь інсталяції, а зміщення в часі: ти перевіряєш застосунок на версії, яку частина аудиторії отримає пізніше. У практиці це дає обидва боки — ранній сигнал про від майбутнього релізу браузера і ризик поганого зворотного: зелений прогін не доказ, що на поточній версії Chrome усе гаразд. Коли потрібен саме брендовий браузер (наприклад, для перевірок, що чіпляють специфіку Chrome чи Edge), його підключають окремим каналом, а не сподіваються на дефолт.
Чому WebKit у Linux-CI не дорівнює WebKit на macOS?
Бо той самий на різних операційних системах поводиться по-різному: частина можливостей сильно залежить від платформи. Найконкретніший приклад із документації — доступні медіакодеки істотно різняться між Linux, macOS і Windows. Тому найдешевший варіант (WebKit на Linux-агентах CI) і найближчий до реального досвіду Safari (WebKit на mac) — це не одне й те саме, і вибір між ними треба робити свідомо. Практичне правило: якщо в застосунку є відтворення відео чи аудіо, WebKit варто ганяти на mac, інакше «зелено в CI» нічого не каже про користувача iPhone або MacBook. Для решти перевірок Linux-агент цілком робочий — і саме тому матриця будується з ризиків продукту, а не з наявних агентів.
Headless — це той самий браузер із прапорцем?
Ні, і це одна з найчастіших хиб інтуїції. Для видимих (headed) прогонів інструмент постачає звичайну збірку Chromium, а для headless — окремий бінарник chromium headless shell; тобто це різні збірки, а не режим одного й того самого бінарника. Додатковий шар плутанини: у брендових Chrome і Edge headless тепер зроблений по-новому — ближче до звичайного видимого режиму — і від дефолтного chromium headless shell він поводиться інакше, причому це очікувано, а не дефект. Практичний наслідок економить години: «локально з вікном зелене, у CI без вікна червоне» цілком може бути різницею збірок, а не багом застосунку чи локатора. Тому перший крок із таким падінням — відтворити локально рівно той режим, що в CI, а не переписувати селектор.
Тест зелений локально, а в CI червоний — з чого почнеш розбір?
Тут перевіряють порядок гіпотез, а не знання фіч. Спершу режим і збірка: локально прогін ішов із вікном, у CI — окремим headless-бінарником, і поведінка тут може легально відрізнятися, тож перше — повторити локально той самий режим. Другий крок — ізоляція: прогнати цей тест окремо, і якщо сам по собі він зелений, підозра переїжджає на спільний стан і взаємозалежні тести, бо це той самий маркер «падає лише в компанії інших». Третій — середовище: інша ОС агента (а з нею інші кодеки й шрифти), інший браузерний канал, інші дані. І лише після цього має сенс дивитися на сам застосунок і на код тесту — інакше є ризик переписувати локатор там, де винна різниця збірок.
Як знання про власні збірки змінює матрицю браузерів?
Воно змінює не код, а домовленості. По-перше, метою не є піксельна ідентичність: сайт не мусить виглядати однаково всюди, доки базова функціональність доступна в кожному підтримуваному браузері — тінь, що у WebKit відрізняється на пару пікселів, це робота , а не дефект. По-друге, повне браузерів і пристроїв недосяжне, тож діапазон підтримки узгоджують із власником продукту й будують із даних про аудиторію, а не зі смаку команди; за мінімальний кістяк беруть базовий набір Baseline — Chrome і Firefox у десктопній та Android-версіях, Edge, плюс Safari для macOS та iOS. По-третє, для більшості перевірок верстки браузери зі спільним рушієм рендерингу окремих рядків матриці не вимагають: Chrome, Edge й Opera тут одна позиція, і третій рядок купує ту саму інформацію втретє. І окремо — у формулюваннях: рядок «Safari» у матриці, що виконується збіркою WebKit, треба або перейменувати, або закривати справжнім Safari поза Playwright.
У WebKit тест на верстку падає, а в Chromium ні. Це дефект застосунку?
Не обовʼязково, і саме тут корисно тримати в голові три причини кросбраузерних розбіжностей: реалізації в самих браузерах різняться й містять вади; можливості підтримані неоднаково; сам пристрій має свої межі. З першої випливає неприємне — винним може виявитися браузер, а не твій код, і тоді тікет іде вендору, а в себе тримають обхідний шлях. Друга і третя часто виглядають як «баг у нас», хоча насправді це відсутня можливість або межа пристрою. Перед висновком корисно перевірити ще два свої боки: чи це не різниця збірки й режиму (свіжа WebKit-збірка проти релізного Safari, headless проти headed) і чи очікування в тесті взагалі про функціональність, а не про пікселі. І головне для звіту: поки в ньому немає платформи, пристрою й версії браузера, локалізувати дефект нема з чого — саме ці три поля відкривають розбір.
Три ситуації, у яких архітектура інструмента вирішує результат роботи: падіння, яке живе тільки в CI; , що ділить один контекст на всіх, і те, у що вона перетворюється після переїзду на ; і чесна матриця браузерів, де рядок конфігу не дорівнює обіцянці в звіті.
Кейс 1. «Локально зелене, у CI червоне»: порядок гіпотез замість переписування локатора
Приходить тікет: тест логіну падає в на кожному другому прогоні, локально не відтворюється. Спокуса — піти правити або підкинути очікування. Архітектурний тріаж дешевший: три перші гіпотези нічого не коштують, а відсікають більшість причин.
| Крок | Що перевіряєш | Як перевірити | Що означає результат |
|---|---|---|---|
| 1 | Режим і збірка | Прогнати локально в тому самому режимі, що в CI (headless), і той самий канал браузера | Відтворилось — винна різниця збірок, а не логіка. Headless тут окремий бінарник, тож поведінка може легально відрізнятися |
| 2 | Ізоляція | Прогнати цей тест окремо, потім у сюїті | Сам зелений, у сюїті червоний — спільний стан і взаємозалежність, лікується свіжою фікстурою |
| 3 | Агент і ОС | Порівняти ОС агента з локальною; чи є в сценарії медіа | Різні кодеки й шрифти між Linux, macOS і Windows дають різний рендеринг і різне відтворення відео |
| 4 | Паралельність | Зменшити воркерів до одного | Позеленіло — гонка за спільними даними або зовнішній ліміт, а не селектор |
| 5 | Застосунок і тест | Трейс, скріншот, логи | Тільки тут зʼявляється сенс правити код тесту |
Що дивитися і чому:
- Крок 1 не «на всяк випадок». Для видимих прогонів інструмент бере звичайну збірку Chromium, для headless — окремий
chromium headless shell, а брендові Chrome і Edge мають ще й свою нову реалізацію headless-режиму, яка від цієї збірки відрізняється. Тобто «те саме, тільки без вікна» — хибна модель, і години на переписування локатора йдуть саме через неї. - Крок 2 має точний маркер. «Сам по собі зелений, у сюїті падає» — це не загальний , а підпис конкретної причини: спільна фікстура, де один тест спирається на результат іншого. тут дасть зелений колір і залишить причину.
- Не міняй кілька змінних за раз. Класична помилка тріажу — одночасно перевести на
--headed, зменшити і оновити браузери: прогін позеленів, причина невідома, а через тиждень усе повернулось. - Фіксуй результат кроку в тікеті. «Локально в headless відтворюється» — це вже висновок про природу дефекту, і саме він визначає, кому тікет адресувати: команді автотестів чи розробникам продукту.
Кейс 2. Сюїта на одному контексті: діагноз і переїзд на фікстури
Успадкована сюїта економила секунди на старті: один процес, один контекст, один логін на всі тести. Симптоми пішли, коли ввімкнули паралельність — кілька тестів почали падати «по черзі», кожен раз різні.
// БУЛО: спільний контекст на весь файл — економія секунд, ціна — протікання стану
import { test, chromium, type Browser, type BrowserContext } from '@playwright/test';
let browser: Browser;
let context: BrowserContext;
test.beforeAll(async () => {
browser = await chromium.launch();
context = await browser.newContext(); // ОДИН профіль на всі тести
const page = await context.newPage();
await page.goto('/login');
// ... логін один раз, кукі лишаються в контексті
});
test.afterEach(async () => {
// спроба прибрати за собою: працює лише для того, про що згадали
const page = context.pages()[0];
await page.evaluate(() => localStorage.clear());
});
Тут два дефекти дизайну одразу. Перший: усі тести бачать кукі й сховище одне одного, тож результат залежить від порядку — а під паралельним прогоном порядок уже не той, під який тести писалися. Другий: afterEach прибирає рівно те, про що згадав автор, і не прибирає того, що прибрати неможливо в принципі — наприклад, уже відвідані посилання.
// СТАЛО: свіжий контекст на кожен тест приходить фікстурою і закривається сам
import { test, expect } from '@playwright/test';
test('кошик нового користувача порожній', async ({ page }) => {
await page.goto('/cart');
await expect(page.getByText('Кошик порожній')).toBeVisible();
});
test('після додавання товару кошик показує його кількість', async ({ page }) => {
await page.goto('/catalog');
await page.getByRole('button', { name: 'Додати до кошика' }).first().click();
await expect(page.getByTestId('cart-count')).toHaveText('1');
});
Той самий дешевий контекст закриває і сценарій, який на одному профілі просто не збирається — дві ролі одночасно:
import { test, expect } from '@playwright/test';
test('покупець бачить повідомлення продавця в чаті', async ({ browser }) => {
// два незалежні профілі в межах одного процесу браузера
const sellerContext = await browser.newContext();
const buyerContext = await browser.newContext();
const seller = await sellerContext.newPage();
const buyer = await buyerContext.newPage();
await seller.goto('/chat/order-42');
await buyer.goto('/chat/order-42');
await seller.getByPlaceholder('Повідомлення').fill('Відправив сьогодні');
await seller.getByRole('button', { name: 'Надіслати' }).click();
await expect(buyer.getByText('Відправив сьогодні')).toBeVisible();
await sellerContext.close();
await buyerContext.close();
});
Що дивитися і чому:
- Економія була уявною. Дорого коштує запуск процесу браузера, а не створення контексту: контекст еквівалентний інкогніто-профілю й створюється майже даром. Спільний контекст економив секунди й купував години розборів.
- Порядок тестів — це і є ізоляція. Поки кожен тест стартує з чистого аркуша, паралельність і безпечні; варто стану протекти — і вони перестають бути безпечними першими.
afterEachне викидай зовсім. Він лишається потрібним для стану поза браузером: створених користувачів, замовлень, файлів. Просто це не заміна свіжому контексту, а доповнення до нього.- Дві ролі — два контексти, не два браузери. Другий процес нічого не додає до ізоляції, зате додає час старту й памʼять на агенті. Контексти в цьому прикладі створені руками, бо їх два — але кожен усе одно закривається явно, як і в бібліотеці.
Кейс 3. Матриця браузерів: рядок конфігу проти обіцянки в звіті
Перед релізом менеджер питає, у яких браузерах перевірено. У конфігу три проєкти, і спокусливо відповісти списком їхніх назв. Точна відповідь інша, і будується вона з розділення «чим прогнали» і «що це доводить».
| Рядок у конфігу | Що реально запускається | Що це доводить | Чого не доводить |
|---|---|---|---|
chromium | Відкрита збірка Chromium, зазвичай на версію попереду брендового | Сценарії працюють на версії Chromium, яка доїде в Chrome і Edge за кілька тижнів | Що все гаразд саме на поточному Chrome у користувача |
firefox | Патчена збірка від команди інструмента | Функціональність працює на рушії Gecko свіжої стабільної версії | Що перевірено брендовий Firefox — із ним інструмент не працює |
webkit (Linux-агент) | Збірка WebKit зі свіжих джерел головної гілки | Що логіка не залежить від специфіки Chromium і Gecko | Що це працює в Safari на macOS чи iOS: медіакодеки й платформозалежні можливості різняться між ОС |
chrome / msedge | Брендовий браузер окремим каналом | Поведінку саме того браузера, що в аудиторії | Нічого про Safari й Firefox |
Далі матриця перестає бути списком браузерів і стає домовленістю. За мінімальний кістяк беруть базовий набір Baseline — Chrome і Firefox у десктопній та Android-версіях, Edge, плюс Safari для macOS та iOS, — а конкретний діапазон узгоджують із власником продукту на даних про аудиторію: повне все одно недосяжне. Браузери зі спільним при цьому займають одну позицію для більшості перевірок верстки: Chrome, Edge й Opera тут в одному рядку.
Що дивитися і чому:
- Перейменуй рядки в звіті. «Safari OK» через проєкт
webkitзакриває тільки на папері. Формулювання «перевірено на збірці WebKit; брендовий Safari — ручна перевірка на macOS 14 та iOS 17» коштує рівно стільки, скільки під ним роботи. - Медіа виносить WebKit на mac. Якщо в продукті є відео чи аудіо, Linux-агент дає найдешевший, але не найпоказовіший прогін — доступні кодеки істотно різняться між ОС.
- Пікселі — не критерій. Мета не в ідентичному вигляді: доки базова функціональність доступна в кожному підтримуваному браузері, різниця тіней і антиаліасингу — робота рушія рендерингу, а не дефект. Це ж рятує від марних порівнянь між рушіями рендерингу.
- Дефект може бути в браузері. Одна з трьох причин кросбраузерних розбіжностей — саме вади й розбіжності реалізацій; тоді тікет іде вендору, а в продукті лишається обхідний шлях. Але будь-який такий звіт починається з платформи, пристрою й версії браузера: без них локалізувати нічого.
Модель керування браузером
- Можу пояснити, чому в Playwright немає окремих драйверів: він ходить до браузера власним протоколом, а браузери й системні залежності ставить сама команда інструмента.
- Знаю різницю трьох моделей керування:
wire-протокол поза процесом браузера (W3C WebDriver, ланцюг local end → intermediary node → endpoint node), власний протокол інструмента, виконання тестового коду всередині браузера. - Не називаю CDP «протоколом Playwright» і не ставлю його четвертою моделлю: це протокол усередині власної моделі, привʼязаний до Chromium. І памʼятаю, що однакова API у надбудов (хелпери CodeceptJS) не означає взаємозамінності бекендів: заголовки запиту ставляться через Playwright і Puppeteer, а через WebDriver ні.
Ієрархія browser → context → page
- Можу без підказки назвати три рівні:
browser— процес,context— ізольований профіль,page— сторінка в цьому профілі. - Знаю різницю бібліотеки й : у бібліотеці я сам обираю тип браузера, запускаю процес, створюю й закриваю контекст; у ранері
pageіcontextприходять вбудованими , створюються ліниво й закриваються самі, а матриця браузерів і пристроїв описана в конфігу, а не правками сценарію. - Памʼятаю, що web-first assertions — властивість ранера, а не бібліотеки, і що моделі різні: у бібліотеці ліміт на операціях (типово 30 секунд), у ранері — на тесті (за замовчуванням теж 30 секунд), а більшість операцій власного таймауту не мають.
Ізоляція, флак і кілька контекстів
- Можу відповісти на «навіщо контекст, якщо є браузер» точно: ізоляція профілю без вартості запуску процесу, а ізолюються кукі,
localStorageіsessionStorage— повністю, навіть коли контексти живуть в одному процесі браузера. - Памʼятаю, що свіжий контекст на кожен тест під ранером — дефолт, а не моя ручна робота.
- Можу назвати три вигоди ізоляції: падіння не переноситься на інший тест; дебажити легше, бо один тест можна прогнати скільки завгодно разів; порядок виконання перестає мати значення для паралельного прогону й .
- Знаю дві стратегії ізоляції й аргументи проти між тестами: про нього легко забути, а частину стану (як відвідані посилання) прибрати неможливо.
- Упізнаю маркер взаємозалежних тестів: сам по собі зелений, у падає при додаванні або прибиранні іншого тесту; причина — спільна фікстура, лікування — свіжа фікстура на кожен тест, а не .
- Знаю, що багатокористувацький сценарій (чат, продавець і покупець) роблять двома контекстами в одному браузері, а не двома браузерами й не логаутом посередині тесту.
Свої браузери: межі обіцянок
- Знаю, які браузери водить інструмент: Chromium, Firefox, WebKit плюс брендові Chrome і Edge окремими каналами; емуляція мобільних і планшетів — режим, не окремий браузер; за замовчуванням іде відкрита збірка Chromium на версію попереду брендового (світ на Chrome N — інструмент уже на Chromium N+1).
- Не кажу «перевірили в Safari», якщо прогін ішов через
webkit: брендовий Safari цим інструментом не керується, бо той тримається на патчах власних збірок; те саме з брендовим Firefox. - Памʼятаю, що той самий на різних ОС поводиться по-різному (найконкретніше — доступні медіакодеки), тому WebKit на Linux-CI не дорівнює WebKit на mac.
Headless і тріаж «локально зелене, у CI червоне»
- Знаю, що headless тут окрема збірка, а не : для видимих прогонів звичайний Chromium, для headless — бінарник
chromium headless shell; а брендові Chrome і Edge мають ще й нову реалізацію headless-режиму, ближчу до видимого, яка від дефолтної збірки відрізняється. - Можу назвати порядок гіпотез при падінні лише в CI: спершу режим і збірка, потім ізоляція (чи тест падає сам по собі), далі середовище й агент, і лише потім застосунок та код тесту.
Матриця браузерів
- Розумію, що мета не піксельна ідентичність: різниця рендерингу на пару пікселів здебільшого не дефект, доки базова функціональність доступна.
- Знаю, що повне браузерів і пристроїв недосяжне, тож діапазон підтримки узгоджують із власником продукту на даних про аудиторію (мінімальний кістяк — Baseline: Chrome, Edge, Firefox плюс Safari для macOS та iOS), а браузери зі спільним для більшості перевірок верстки займають один рядок, а не три.
- Знаю три причини кросбраузерних дефектів (реалізації різняться й містять вади, можливості підтримані неоднаково, пристрій має свої межі), що з першої випливає баг у браузері, який заводять вендору, і що звіт без платформи, пристрою й версії браузера нічого не дає.
Квіз
Перед стартом
- Питань: 16
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Ієрархія обʼєктів Playwright — три рівні й що означає кожен

