Playwright и Puppeteer имеют много общего: оба фреймворка предоставляют интерфейсы для автоматизации браузеров на основе Chromium, Firefox и WebKit. Однако у Playwright есть расширенные возможности, которые делают его более универсальным для комплексного тестирования и кросс-браузерной автоматизации.
Главные различия между Puppeteer и Playwright:
waitForSelector.В Puppeteer стандартный код выглядит так:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');
})();
В Playwright этот же сценарий становится более универсальным:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
})();
Ключевой момент: создание контекста
newContext() в Playwright обеспечивает полную изоляцию
данных (cookies, localStorage, sessionStorage), чего нет в Puppeteer по
умолчанию.
Puppeteer требует явного ожидания элементов:
await page.waitForSelector('#login');
await page.click('#login');
Playwright сочетает действие и ожидание:
await page.locator('#login').click();
locator автоматически ожидает доступность элемента,
видимость и возможность клика. Дополнительно можно применять фильтры и
цепочки условий:
await page.locator('button', { hasText: 'Submit' }).click();
В Puppeteer ввод текста выполняется через type:
await page.type('#username', 'admin');
await page.type('#password', '1234');
await page.click('#submit');
Playwright упрощает работу с текстом, используя методы
fill и press:
await page.locator('#username').fill('admin');
await page.locator('#password').fill('1234');
await page.locator('#submit').click();
fill автоматически очищает поле перед вводом, что
снижает вероятность ошибок при автозаполнении или предыдущих
значениях.
Playwright предоставляет встроенные возможности перехвата сетевых запросов без дополнительных библиотек:
await page.route('**/api/**', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ success: true })
});
});
Также возможно эмулировать замедленную сеть и геолокацию:
await context.setOffline(true);
await context.setGeolocation({ latitude: 55.7558, longitude: 37.6173 });
В Puppeteer для скриншотов используется метод
screenshot:
await page.screenshot({ path: 'example.png', fullPage: true });
Playwright добавляет возможность делать скриншоты конкретных элементов:
await page.locator('#main').screenshot({ path: 'main.png' });
Одно из главных преимуществ Playwright — одинаковый API для всех браузеров:
const { chromium, firefox, webkit } = require('playwright');
for (const browserType of [chromium, firefox, webkit]) {
const browser = await browserType.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
await browser.close();
}
Такой подход позволяет запускать одни и те же сценарии без изменений в коде, что экономит время и упрощает поддержку тестов.
Playwright поддерживает работу с всплывающими окнами, iframes и элементами shadow DOM более удобно, чем Puppeteer. Пример работы с iframe:
const frame = page.frame({ url: /iframe-url/ });
await frame.locator('button#submit').click();
Для shadow DOM:
await page.locator('my-component >>> button').click();
Создание нескольких контекстов позволяет запускать параллельные сценарии без открытия новых браузеров:
const context1 = await browser.newContext();
const context2 = await browser.newContext();
const page1 = await context1.newPage();
const page2 = await context2.newPage();
Каждый контекст изолирован, что особенно удобно для тестов с разными учетными записями.
Playwright изначально рассчитан на использование с TypeScript, что повышает безопасность кода и автокомплит в IDE:
import { chromium, Browser, Page } from 'playwright';
let browser: Browser;
let page: Page;
browser = await chromium.launch();
const context = await browser.newContext();
page = await context.newPage();
Типизация помогает избежать ошибок при работе с элементами и сетевыми запросами.