За последний месяц я насчитал минимум семь свежих статей с заголовком в духе "Playwright быстрее Selenium на N%". Проблема в том, что N у всех разный: 23%, 42%, 63%, "1.85x". Методология почти нигде не раскрыта дальше фразы "controlled environment". Для решения, которое определяет CI-бюджет и архитектуру тестов на годы вперёд, это не цифры — это шум.
Здесь — что из этого шума реально на что-то опирается, почему остальное несопоставимо, и рабочий бенчмарк-харнесс, который вы можете прогнать на своём стеке за один CI-job и получить именно свои числа, а не чужие проценты.

Почему вообще должна быть разница
Все четыре инструмента по-разному говорят с браузером, и это архитектурное решение — не деталь, а главная причина разницы в скорости.
Selenium работает через протокол WebDriver: команда из теста идёт HTTP-запросом к драйверу браузера (chromedriver/geckodriver), тот транслирует её в нативный вызов. Каждое действие — это запрос-ответ по HTTP, и эта связка добавляет задержку на каждом шаге. Selenium 4 добавил протокол BiDi (двунаправленный, поверх WebSocket) для части операций — сетевого перехвата, логов консоли, — но базовое исполнение команд по-прежнему идёт через HTTP-слой WebDriver.
Cypress в принципе не выходит за пределы браузера: тестовый раннер исполняется в том же event loop, что и тестируемое приложение, без какого-либо внешнего протокола между ними. Это даёт нулевую сетевую задержку на каждое действие, но ценой архитектурных ограничений — Cypress не может по-настоящему управлять вторым табом, потому что сам раннер занимает iframe рядом с приложением.
Playwright подключается к браузерам напрямую по их нативным debug-протоколам — Chrome DevTools Protocol для Chromium, патченый Marionette для Firefox, WebKit Inspector Protocol для WebKit — через постоянное WebSocket-соединение. HTTP-слоя между тестом и браузером нет в принципе.
WebdriverIO — особый случай: он может работать и через классический WebDriver-протокол (тогда архитектурно близок к Selenium), и через DevTools/BiDi-протокол. Поэтому в части бенчмарков WDIO попадает в категорию "быстрый", а в части — в категорию "как Selenium", и это зависит исключительно от того, какой драйвер выбрал автор теста.
Из этого уже можно сделать архитектурный вывод без единого замера: WebSocket-протоколы (Playwright, WDIO в DevTools-режиме) структурно не могут быть медленнее, чем HTTP-polling (классический WebDriver), при прочих равных. Вопрос не "будет ли разница", а "насколько она проявится на конкретном тест-сьюте".
Что из опубликованного действительно похоже на бенчмарк
Один из немногих источников, который раскрывает методологию — серия постов Checkly (компания, которая делает synthetic monitoring, то есть сама эксплуатирует эти инструменты в проде, а не продаёт TMS или дашборд для них). Они гоняли одинаковые E2E-сценарии против реальных сайтов на одинаковой инфраструктуре несколько тысяч раз подряд.
Несколько выводов оттуда, которые стоит учитывать:
В сценарии с короткими одиночными тестами разрыв между Cypress и остальными инструментами был выражен сильнее всего из-за времени старта раннера; на сьютах из нескольких тестов подряд этот разрыв ощутимо сокращается за счёт амортизации стартовых издержек.
При исполнении сьюта (а не одиночного теста) Cypress оказался медленнее самого быстрого инструмента (Playwright) примерно на 23%, и при этом лишь на ~3% медленнее, чем связка WebDriverIO+Selenium, которая в этом прогоне была самой медленной.
WebDriverIO в режиме DevTools-протокола показал заметно более высокую вариативность времени исполнения, чем остальные инструменты — то есть медиана может быть неплохой, а вот p95 — нет, и для CI это часто важнее средней цифры.
В реальных сценариях именно Playwright показал наименьшую вариативность времени исполнения среди всех протестированных инструментов, что для CI-стабильности значит больше, чем чистая скорость.
Отдельно, по доле рынка — это не бенчмарк скорости, но это реальные данные опроса, а не маркетинговый текст: по данным State of JS 2024, доля Playwright выросла с 9% в 2023 году до 15% в 2024-м, и опрос назвал его самой быстрорастущей по принятию технологией тестирования того года.
Это, по сути, всё, что я нашёл с раскрытой методологией и без явного коммерческого интереса в результате.
А вот это — нет
Дальше идёт ворох свежих (2026 год) постов от компаний, которые продают платформы вокруг этих фреймворков — TMS-аналитику, дашборды для CI, AI-ревью прогонов. Формально у них тоже написано "controlled benchmark", но цифры между собой не бьются, и это видно невооружённым глазом:
Источник | Заявленная разница (Playwright vs Selenium) | Как обоснована |
|---|---|---|
TestDino (блог №1, февраль 2026) | "на ~290 мс/действие vs 536 мс у Selenium" | Без описания стенда и кол-ва прогонов |
TestDino (блог №2, апрель 2026) | "на 42% быстрее" | Ссылка на "внутреннюю аналитику" компании |
Techoral | "на 63% быстрее, на 82% меньше флака" | "1000 тестов", окружение не описано |
Vervali Systems | "в 1.85 раза быстрее" | Без сырых данных |
Разброс от 42% до 63% при формально одинаковой постановке вопроса — это не погрешность измерения, это разные (или вообще не проводившиеся) замеры, упакованные в уверенный тон. Часть этих текстов прямо признаётся, что данные "собраны из трёх источников", то есть это уже не бенчмарк, а агрегация чужих маркетинговых чисел, выданная за новое исследование. Использовать такие цифры в технической статье на Хабре — то же самое, что цитировать рекламную листовку как research paper.
Вывод: если у вас на проекте есть конкретный тест-сьют и конкретная CI-инфраструктура, единственное число, которому стоит доверять — то, которое вы получите сами. Дальше — харнесс для этого.
Бенчмарк-харнесс: один и тот же сценарий на четырёх инструментах
Идея: один и тот же flow (логин → переход в раздел → клик по трём элементам → проверка состояния), реализованный нативными средствами каждого фреймворка, прогнанный N раз подряд на одной и той же CI-машине, с фиксированными версиями браузеров.
Тестовое приложение
Берите свой реальный staging, либо локальный fixture-сервер на Express — главное, чтобы все четыре инструмента ходили в один и тот же инстанс с одинаковой задержкой сети (то есть localhost, не реальный CDN, иначе сетевой джиттер забьёт разницу между фреймворками).
// fixture-server.js — минимальное SPA-подобное приложение для замера const express = require('express'); const app = express(); app.use(express.urlencoded({ extended: true })); app.get('/login', (_, res) => res.send(` <form method="post" action="/login"> <input name="user" /><input name="pass" type="password" /> <button type="submit">Войти</button> </form>`)); app.post('/login', (_, res) => res.redirect('/dashboard')); app.get('/dashboard', (_, res) => res.send(` <div id="items"> <button data-id="1">Item 1</button> <button data-id="2">Item 2</button> <button data-id="3">Item 3</button> </div> <div id="status">idle</div> <script> document.querySelectorAll('button').forEach(b => b.onclick = () => document.getElementById('status').innerText = 'clicked-' + b.dataset.id); </script>`)); app.listen(3000);
Playwright
// playwright.spec.ts import { test, expect } from '@playwright/test'; test('login + interact flow', async ({ page }) => { await page.goto('http://localhost:3000/login'); await page.fill('input[name=user]', 'qa'); await page.fill('input[name=pass]', 'qa'); await page.click('button[type=submit]'); await page.waitForURL('**/dashboard'); for (const id of [1, 2, 3]) { await page.click(`button[data-id="${id}"]`); } await expect(page.locator('#status')).toHaveText('clicked-3'); });
npx playwright test --reporter=json --workers=1 --repeat-each=50 > pw-results.json
Cypress
// cypress/e2e/flow.cy.js describe('login + interact flow', () => { it('runs the flow', () => { cy.visit('http://localhost:3000/login'); cy.get('input[name=user]').type('qa'); cy.get('input[name=pass]').type('qa'); cy.get('button[type=submit]').click(); cy.url().should('include', '/dashboard'); [1, 2, 3].forEach((id) => cy.get(`button[data-id="${id}"]`).click()); cy.get('#status').should('have.text', 'clicked-3'); }); });
npx cypress run --reporter json --spec cypress/e2e/flow.cy.js > cy-results.json
WebdriverIO (в DevTools/Bidi-режиме — для честного сравнения с Playwright)
// wdio.flow.spec.js describe('login + interact flow', () => { it('runs the flow', async () => { await browser.url('http://localhost:3000/login'); await $('input[name=user]').setValue('qa'); await $('input[name=pass]').setValue('qa'); await $('button[type=submit]').click(); await browser.waitUntil(async () => (await browser.getUrl()).includes('/dashboard')); for (const id of [1, 2, 3]) { await $(`button[data-id="${id}"]`).click(); } await expect($('#status')).toHaveText('clicked-3'); }); });
Selenium (Node binding, классический WebDriver-протокол)
// selenium.flow.js const { Builder, By, until } = require('selenium-webdriver'); (async () => { const driver = await new Builder().forBrowser('chrome').build(); const t0 = performance.now(); try { await driver.get('http://localhost:3000/login'); await driver.findElement(By.name('user')).sendKeys('qa'); await driver.findElement(By.name('pass')).sendKeys('qa'); await driver.findElement(By.css('button[type=submit]')).click(); await driver.wait(until.urlContains('/dashboard'), 5000); for (const id of [1, 2, 3]) { await driver.findElement(By.css(`button[data-id="${id}"]`)).click(); } await driver.wait(until.elementTextContains(driver.findElement(By.id('status')), 'clicked-3'), 5000); } finally { console.log(JSON.stringify({ duration_ms: performance.now() - t0 })); await driver.quit(); } })();
Для Selenium придётся самостоятельно обернуть замер времени (как выше) — встроенного репортера с таймингами на уровне теста, как у остальных трёх, нет из коробки.
Условия, без которых сравнение бессмысленно
Один и тот же раннер:
ubuntu-22.04, фиксированное число vCPU/RAM (GitHub Actions:ubuntu-latest, без переменной нагрузки от соседних джобов в матрице).Headless-режим везде — иначе сравниваете не фреймворки, а рендеринг GUI.
Фиксированные, явно прописанные версии браузеров (
npx playwright install --with-deps chromium@<version>,chromedriverтой же мажорной версии, что и Chrome в раннере) — рассинхрон версий браузера и драйвера у Selenium даёт случайный шум, который легко спутать с архитектурной разницей.Минимум 30–50 повторов на инструмент, отчёт по медиане и p95, а не по одному прогону — отдельные запуски шумят на 20–40% даже в рамках одного фреймворка.
Один и тот же flow, написанный максимально close-to-idiomatic для каждого инструмента (не нужно искусственно занижать Selenium через явные
sleep(), которые никто в проде не пишет — но и не нужно подсовывать ему оптимизации, недоступные в реальном коде команды).
Как считать результат
node -e " const fs = require('fs'); const runs = JSON.parse(fs.readFileSync(process.argv[1])).map(r => r.duration_ms).sort((a,b)=>a-b); const median = runs[Math.floor(runs.length/2)]; const p95 = runs[Math.floor(runs.length*0.95)]; console.log({ median, p95, runs: runs.length }); " results.json
Прогоните так каждый инструмент трижды в разные дни (CI-раннеры — общий ресурс, шум от соседей реален), сравните медианы и p95 между прогонами одного и того же фреймворка — если они расходятся больше чем на 10–15%, ваш стенд недостаточно стабилен для выводов, и сначала нужно разбираться с этим, а не с выбором фреймворка.
Что можно сказать без замеров, и что нельзя
Без единого личного замера, опираясь только на архитектуру и на источники с раскрытой методологией, можно уверенно сказать:
WebSocket-протоколы (Playwright, WDIO в BiDi-режиме) структурно быстрее на каждое отдельное действие, чем HTTP-polling классического WebDriver. Это не зависит от вендора и не может "развернуться" на каком-то конкретном стенде.
На сьютах (а не одиночных тестах) разрыв между Cypress и Playwright меньше, чем на коротких прогонах — стартовые издержки амортизируются.
Стабильность (variance, p95) для CI часто важнее средней скорости — это явно показано в данных Checkly, и это игнорируют почти все вендорские посты, концентрируясь на одном эффектном проценте в заголовке.
Чего нельзя сказать без своего замера — это любое конкретное "X% быстрее" для вашего стека. Слишком много переменных: размер DOM, количество сетевых запросов на странице, тип selectors (CSS vs XPath vs role-based), параллелизм в CI, версии браузеров. Те же 23% у Checkly и 63% у Techoral — это не противоречие в "правде", это просто два разных приложения и два разных метода счёта.
Резюме
Если вам нужно решение "на сейчас" без замеров — архитектура даёт достаточно сигнала: для нового проекта на вебе Playwright или WDIO в BiDi-режиме — разумный default по скорости и стабильности, Cypress — если важнее DX для фронтенд-команды и сьюты достаточно длинные, чтобы амортизировать старт, Selenium — если у вас уже большая инвестиция в Java/C#/Ruby-инфраструктуру и WebDriver Grid, который работает.
Если решение нужно обосновать цифрами перед руководством — не берите процент из чужого блога. Прогоните харнесс выше на своём стеке, на своём приложении, в своём CI — это займёт один рабочий день и даст вам единственное число, которому вы сможете доверять и которое сможете защитить, если кто-то спросит "а как считали".