E2E-тесты WordPress с Playwright
Что такое E2E-тестирование
Заголовок раздела «Что такое E2E-тестирование»End-to-end (E2E) тесты — это тесты, которые симулируют действия реального пользователя в браузере. В отличие от unit-тестов, которые проверяют изолированные функции, E2E-тесты работают на макро-уровне: они взаимодействуют с полным стеком приложения — фронтендом, бэкендом и базой данных.
E2E-тесты особенно полезны для:
- Критических пользовательских сценариев (логин, оформление заказа, создание контента)
- Проверки блоков и паттернов в редакторе Gutenberg
- Верификации фронтенд-вывода после настройки через REST API
Ограничения: E2E-тесты медленнее и хрупче unit-тестов. Изменение в любом слое (UI, сеть, БД) может сломать тест. Их стоит использовать для ключевых сценариев, а не пытаться покрыть весь код.
Инструменты
Заголовок раздела «Инструменты»WordPress для E2E-тестирования использует Playwright — современный, надёжный и широко распространённый фреймворк. Ранее в WordPress использовался Puppeteer, но с 2022 года проект перешёл на Playwright.
| Инструмент | Назначение |
|---|---|
@playwright/test | Фреймворк для написания и запуска E2E-тестов |
@wordpress/e2e-test-utils-playwright | WordPress-хелперы: авто-логин, createNewPost(), visitAdminPage() |
@wordpress/env (wp-env) | Локальное WordPress-окружение в Docker |
@wordpress/scripts | Набор скриптов, включая test-playwright |
Настройка окружения
Заголовок раздела «Настройка окружения»1. Локальное окружение с wp-env
Заголовок раздела «1. Локальное окружение с wp-env»wp-env запускает WordPress в Docker-контейнере. Это официальный инструмент от WordPress, который минимизирует время настройки.
# Установкаnpm install @wordpress/env --save-dev
# Создание конфигурации .wp-env.jsoncat > .wp-env.json << 'EOF'{ "$schema": "https://schemas.wp.org/trunk/wp-env.json", "themes": [ "." ], "lifecycleScripts": { "afterStart": "THEME_SLUG=$(basename \"$PWD\"); for SERVICE in cli tests-cli; do wp-env run \"$SERVICE\" wp theme activate \"$THEME_SLUG\"; done" }}EOF
# Добавление скрипта в package.json# "scripts": { "wp-env": "wp-env" }
# Запуск окруженияnpx wp-env startПосле запуска будут доступны:
http://localhost:8888— среда разработкиhttp://localhost:8889— тестовая среда
2. Установка Playwright
Заголовок раздела «2. Установка Playwright»# Установка пакетовnpm install @playwright/test @wordpress/e2e-test-utils-playwright --save-dev
# Установка браузеров и системных зависимостейnpx playwright install --with-deps3. Файл конфигурации
Заголовок раздела «3. Файл конфигурации»Создайте playwright.config.js в корне проекта:
export { default } from '@wordpress/scripts/config/playwright.config.js';Это использует стандартную конфигурацию WordPress, которая:
- Автоматически запускает и останавливает
wp-env - Настраивает базовый URL и аутентификацию
- Определяет директорию
specs/для тестов
Кастомизация (при необходимости):
import { defineConfig } from '@playwright/test';import baseConfig from '@wordpress/scripts/config/playwright.config';
export default defineConfig( { ...baseConfig, testDir: './tests/e2e/', // своя директория вместо specs/} );4. Проверка установки
Заголовок раздела «4. Проверка установки»npx wp-scripts test-playwrightОжидаемый вывод: Error: No tests found — тестов ещё нет, но конфигурация работает.
Первый тест: проверка дашборда
Заголовок раздела «Первый тест: проверка дашборда»Создайте specs/main.spec.js:
import { test, expect } from '@wordpress/e2e-test-utils-playwright';
test( 'Loads WordPress dashboard', async ( { admin, page } ) => { await admin.visitAdminPage( '/' ); await expect( page.getByRole( 'heading', { name: 'Welcome to WordPress', level: 2 } ) ).toBeVisible();} );Разбор теста:
admin.visitAdminPage('/')— WordPress-хелпер, который переходит на/wp-admin/, обрабатывает экраны обновления и проверяет что пользователь залогиненpage.getByRole('heading', ...)— Playwright-локатор, использующий accessibility roles (рекомендованный способ)expect(...).toBeVisible()— асинхронное утверждение (assertion)
Запуск:
npx wp-scripts test-playwrightВажно понимать: при использовании стандартного WordPress-тулинга все тесты запускаются от имени администратора (авто-логин). Для тестирования от посетителя нужно либо разлогиниться, либо открыть отдельную страницу без авторизации.
UI Mode
Заголовок раздела «UI Mode»Playwright has встроенный UI Mode для отладки:
npx wp-scripts test-playwright --uiОткрывает браузер с инспектором тестов — можно смотреть пошаговое выполнение, снепшоты и ошибки.
Паттерн AAA: Arrange — Act — Assert
Заголовок раздела «Паттерн AAA: Arrange — Act — Assert»Все E2E-тесты следуют трёхфазному паттерну:
- Arrange — подготовка предусловий (создать пост, установить мета-поля)
- Act — выполнение действий (кликнуть, заполнить, вставить блок)
- Assert — проверка результата (видимость элемента, текст, атрибуты)
В реальных E2E-тестах эти фазы могут чередоваться (несколько act-assert циклов в одном тесте).
Тестирование вариаций блоков
Заголовок раздела «Тестирование вариаций блоков»Допустим, тема регистрирует вариацию блока Paragraph с именем «Book Author», которая использует Block Bindings API для привязки к мета-полю themeslug_book_author.
Планирование теста
Заголовок раздела «Планирование теста»Мысленно представьте ручное тестирование:
- Создать новую запись
- Открыть Inserter блоков
- Найти «Book Author» среди доступных блоков
- Кликнуть для вставки
- Проверить, что блок отображает значение мета-поля
Переведите эти шаги в код:
test( 'Inserts Book Author block', async ( { admin, page, editor } ) => { // Arrange + Act: создать пост и вставить блок await admin.createNewPost();
await page .getByRole( 'button', { name: 'Block Inserter' } ) .click();
await page .getByRole( 'region', { name: 'Block Library' } ) .getByRole( 'listbox', { name: 'Widgets' } ) .getByRole( 'option', { name: 'Book Author', exact: true } ) .click();
// Assert через проверку атрибутов блока await expect.poll( editor.getBlocks ).toMatchObject( [ { name: 'core/paragraph', attributes: { metadata: { bindings: { content: { source: 'core/post-meta', args: { key: 'themeslug_book_author' }, }, }, }, placeholder: 'Book Author', }, } ] );
// Assert через проверку отображаемого значения await page.evaluate( () => wp.data .dispatch( 'core/editor' ) .editPost( { meta: { themeslug_book_author: 'Jane Austen' } } ) );
const bookAuthorBlock = editor.canvas.getByRole( 'document', { name: 'Block: Paragraph', } ); await expect( bookAuthorBlock ).toHaveText( 'Jane Austen' );} );Ключевые моменты
Заголовок раздела «Ключевые моменты»expect.poll(editor.getBlocks)— опрашивает состояние блоков асинхронно. Вставка блока — асинхронная операция, безpollтест может упасть, если блоки ещё не готовыpage.evaluate()— выполняет код в контексте страницы, даёт доступ к глобальномуwp.dataдля программной установки мета-полейeditor.canvas.getByRole()— поиск элементов внутри canvas редактора (iframe с контентом)
Best practices для селекторов
Заголовок раздела «Best practices для селекторов»WordPress рекомендует использовать accessible selectors (getByRole, getByLabelText, getByText). CSS-селекторы и XPath — только когда accessibility-селекторы невозможны.
DevTools браузера умеют показывать accessibility tree: в Chrome — вкладка Accessibility или флаг Full accessibility tree.
Тестирование паттернов со снепшотами
Заголовок раздела «Тестирование паттернов со снепшотами»Паттерны содержат много блоков — проверять каждый по-отдельности громоздко. Вместо этого используйте snapshot testing — сохранение эталонного состояния и сравнение с ним.
Вставка паттерна
Заголовок раздела «Вставка паттерна»test( 'Inserts Book Review Card pattern', async ( { admin, page, editor } ) => { await admin.createNewPost();
await page .getByRole( 'button', { name: 'Block Inserter' } ) .click();
await page.getByRole( 'tab', { name: 'Patterns' } ).click(); await page.getByRole( 'tab', { name: 'Book Reviews' } ).click();
await page .getByRole( 'listbox', { name: 'Book Reviews' } ) .getByRole( 'option', { name: 'Book Review Card' } ) .click();
// Снепшот-утверждение const bookReviewCardPattern = editor.canvas.getByRole( 'document', { name: 'Block: Columns', } ); await expect( bookReviewCardPattern ).toMatchAriaSnapshot();} );Генерация снепшотов
Заголовок раздела «Генерация снепшотов»При первом запуске тест упадёт с ошибкой — снепшота ещё нет:
npx wp-scripts test-playwright# Error: A snapshot doesn't exist at specs/__snapshots__/...aria.yml, writing actual.Сгенерируйте снепшоты:
npx wp-scripts test-playwright --update-snapshotsСоздастся YAML-файл с accessibility-деревом паттерна (specs/__snapshots__/). Теперь тест будет сверять текущее состояние с эталонным снепшотом.
Важно: Используйте --update-snapshots только когда намеренно хотите обновить снепшоты.
Тестирование фронтенда через REST API
Заголовок раздела «Тестирование фронтенда через REST API»Если способ создания контента не важен для теста, можно создать пост через REST API, минуя редактор. Это резко сокращает код теста.
test( 'Displays book review meta on the frontend', async ( { page, requestUtils,} ) => { // Arrange: создать пост с мета-полями через REST API const newPost = await requestUtils.createPost( { status: 'publish', title: 'Emma', content: '', meta: { themeslug_book_author: 'Jane Austen', themeslug_book_rating: '5', themeslug_book_length: '477', themeslug_book_goodreads_url: 'https://www.goodreads.com/book/show/6969.Emma', }, } );
// Act: перейти на страницу созданного поста await page.goto( `?p=${ newPost.id }` );
// Assert: проверить отображение на фронтенде await expect( page.getByText( '5 / 5 Stars' ) ).toBeVisible(); await expect( page.getByText( '477 Pages' ) ).toBeVisible(); await expect( page.getByText( 'Written by Jane Austen' ) ).toBeVisible(); await expect( page.getByRole( 'link', { name: 'View on Goodreads' } ) ).toHaveAttribute( 'href', 'https://www.goodreads.com/book/show/6969.Emma' );} );Хелпер requestUtils.createPost() — часть пакета @wordpress/e2e-test-utils-playwright. Он работает с REST API напрямую.
Команды и флаги
Заголовок раздела «Команды и флаги»| Команда | Описание |
|---|---|
npx wp-scripts test-playwright | Запуск всех тестов |
npx wp-scripts test-playwright --ui | UI Mode для отладки |
npx wp-scripts test-playwright --update-snapshots | Обновление снепшотов |
npx playwright test --grep "pattern name" | Запуск конкретных тестов по имени |
Best practices
Заголовок раздела «Best practices»1. Используйте accessible selectors
Заголовок раздела «1. Используйте accessible selectors»// ✅ Хорошоpage.getByRole( 'button', { name: 'Block Inserter' } )
// ⚠️ Приемлемо, если нет accessibility-альтернативыpage.locator( '.block-editor-inserter__toggle' )
// ❌ Плохо: хрупко, зависит от структуры DOMpage.locator( 'button:nth-child(3)' )2. Используйте expect.poll() для асинхронных операций
Заголовок раздела «2. Используйте expect.poll() для асинхронных операций»// ✅ Правильно — ждёт готовностиawait expect.poll( editor.getBlocks ).toMatchObject( expected );
// ❌ Может упасть из-за race conditionexpect( editor.getBlocks() ).toMatchObject( expected );3. Отдавайте предпочтение REST API для настройки
Заголовок раздела «3. Отдавайте предпочтение REST API для настройки»Если тест проверяет фронтенд, создавайте контент через requestUtils.createPost(), а не через UI редактора. Это быстрее и надёжнее.
4. Снепшоты для сложных структур
Заголовок раздела «4. Снепшоты для сложных структур»Для паттернов и макетов из многих блоков используйте toMatchAriaSnapshot() вместо проверки каждого блока отдельно.
5. Не гонитесь за 100% покрытием E2E
Заголовок раздела «5. Не гонитесь за 100% покрытием E2E»E2E-тесты медленные. Используйте их для критических пользовательских сценариев. Дополняйте unit- и интеграционными тестами.
Дальнейшие шаги
Заголовок раздела «Дальнейшие шаги»- Playwright: Writing Tests — больше действий и утверждений
- Playwright: Test Hooks —
beforeEach,afterEachдля организации тестов - Playwright: Fixtures — вынос переиспользуемой логики из тестов
- Playwright: CI Setup — запуск тестов на каждый коммит или PR
- WordPress Core E2E Tests — реальные примеры тестов блоков
- WordPress E2E Testing Overview — рекомендации Core-команды
- Playwright: Test Agents — куда движется технология