Що таке CDP (Chrome DevTools Protocol) і як він пов’язаний з Playwright?

Щоб зрозуміти CDP — спочатку треба розділити два рівні які не мають між собою нічого спільного.

Рівень 1 — код аплікейшину (твій React/JS сайт)

Звичайний JavaScript який виконується всередині браузера. Взаємодіє з браузером через вбудовані браузерні API — documentwindowfetch. Ніякого CDP тут немає.

Рівень 2 — CDP (Chrome DevTools Protocol)

Канал для зовнішніх програм які хочуть керувати браузером ззовні. Це набір JSON команд які летять через WebSocket між зовнішньою програмою і браузером. CDP — це “розетка” яку Chrome надає зовнішнім програмам. Підключитись може будь-хто хто знає протокол.

Зовнішня програма (Playwright, DevTools)
        ↓ CDP через WebSocket
   Браузер (Chrome engine)
        ↓ виконує JS
   Код аплікейшину (React, ванільний JS)

Хто використовує CDP:

  • DevTools — коли відкриваєш F12. Це не “вбудована частина Chrome” — це окремий веб-додаток який спілкується з браузером через CDP. Вкладки Elements, Network, Console — все через CDP
  • Playwright — керує браузером через CDP: клік, навігація, перехоплення мережі
  • Puppeteer — бібліотека від Google, попередник Playwright, теж CDP
  • Lighthouse — вимірює performance через CDP
  • VS Code debugger — дебагінг Node.js теж через CDP

Аналогія: браузер — це телевізор. Код сайту — відео що грає на екрані. CDP — пульт керування ззовні. DevTools, Playwright, Lighthouse — різні пристрої які підключаються до одного пульта. Самому відео пульт не потрібен — воно просто грає.

TypeScript — як виглядають CDP команди під капотом

// Коли ти пишеш звичайний Playwright код:
await page.goto('https://myshop.com');
await page.locator('.add-to-cart').click();

// Playwright під капотом надсилає CDP команди через WebSocket:
// → { "method": "Page.navigate", "params": { "url": "https://myshop.com" } }
// ← { "result": { "frameId": "abc123" } }
//
// → { "method": "DOM.querySelector", "params": { "selector": ".add-to-cart" } }
// ← { "result": { "nodeId": 42 } }
//
// → { "method": "Input.dispatchMouseEvent", "params": { "type": "click" } }
// ← { "result": {} }
//
// Ти цього не бачиш — Playwright робить це автоматично

TypeScript — прямий доступ до CDP в тесті через newCDPSession

// Зазвичай CDP не треба викликати напряму — Playwright все робить сам
// Але для просунутих речей є прямий доступ:

const client = await page.context().newCDPSession(page);
// ↑ відкриваємо CDP сесію для конкретної вкладки

// Вмикаємо domain Performance і отримуємо метрики
await client.send('Performance.enable');
const { metrics } = await client.send('Performance.getMetrics');
console.log(metrics); // JSHeapUsedSize, LayoutCount, TaskDuration...

// Емулюємо мобільну мережу через CDP
await client.send('Network.emulateNetworkConditions', {
  offline: false,
  downloadThroughput: 1.5 * 1024 * 1024 / 8, // 1.5 Mbps
  uploadThroughput: 750 * 1024 / 8,
  latency: 40,
});

🔧 TypeScript / JS патерни в цьому прикладі page.context().newCDPSession(page) — ланцюжок методів, повертає Promise з CDP client; client.send('Domain.method', params) — надсилає CDP команду, перший аргумент — рядок у форматі “Domain.method”, другий — об’єкт параметрів; деструктуризація const { metrics } = await client.send(...) — беремо поле metrics з результату.

🗣 Як читати вголос CDP — Chrome DevTools Protocol — це канал для зовнішніх програм які хочуть керувати браузером ззовні. Важливо розрізняти два рівні: код аплікейшину — звичайний JavaScript всередині браузера, він використовує браузерні API типу document і fetch, CDP тут немає. CDP — це окремий рівень для зовнішніх програм: набір JSON команд які летять через WebSocket від зовнішньої програми до браузера. Найбільший користувач CDP — самі DevTools які ти відкриваєш через F12: це не вбудована частина Chrome, а окремий веб-додаток що спілкується з браузером через CDP. Playwright теж використовує CDP — коли ти пишеш page.goto() або locator.click(), Playwright автоматично надсилає відповідні CDP команди. Для просунутих речей — performance метрики, емуляція мережі — можна відкрити CDP сесію напряму через newCDPSession і надсилати команди самостійно через client.send().