vyvchy
    Теми розділу

    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, серверні бібліотеки не імпортуються, а двома браузерами одночасно ця модель не керує.

    Модель 3 — виконання в браузері

    Тестовий код
    у самому браузері

    Застосунок
    під тестом

    Модель 2 — власний протокол

    Тестовий код
    (клієнт інструмента)

    Браузер
    (збірка інструмента)

    Модель 1 — wire-протокол

    Тестовий код
    (будь-яка мова)

    Драйвер
    (окрема програма)

    Браузер
    (системний, брендовий)

    Модель 3 — виконання в браузері

    Тестовий код
    у самому браузері

    Застосунок
    під тестом

    Модель 2 — власний протокол

    Тестовий код
    (клієнт інструмента)

    Браузер
    (збірка інструмента)

    Модель 1 — wire-протокол

    Тестовий код
    (будь-яка мова)

    Драйвер
    (окрема програма)

    Браузер
    (системний, брендовий)

    А де тут 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 — сторінка всередині цього профілю, і саме з нею працюють навігація, й дії.

    browser — процес браузера
    запускається один раз

    context 1
    свої кукі, localStorage

    context 2
    інші кукі, інше localStorage

    page

    page (попап)

    page

    browser — процес браузера
    запускається один раз

    context 1
    свої кукі, localStorage

    context 2
    інші кукі, інше localStorage

    page

    page (попап)

    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 — свіжа фікстура на тест як усунення нестабільності.

    Можливі питання

    Пояснення

    «Поясни» працює з власним API-ключем Anthropic: запит іде з вашого браузера прямо до Anthropic.

    Свій API-ключ (BYOK)

    Вставте власний ключ Anthropic — пояснення працюватиме на реальній моделі. Ключ зберігається лише у вашому браузері (localStorage), нікуди не надсилається, крім api.anthropic.com, і не логується.