В этом руководстве вы изучите возможности Playwright, проведете сквозное (end-to-end) тестирование на React-версии известного проекта TodoMVC.
Этот проект служит эталоном для сравнения реализации различных JavaScript-фреймворков на одном приложении. Не волнуйтесь, если вы не знакомы с React — основное внимание уделяется тестированию с помощью Playwright, а не особенностям React.
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Содержание:
- Шаг 1 – Настройка React-демо проекта
- Шаг 2 – Настройка Playwright
- Шаг 3 – Написание первого теста
- Шаг 4 – Изучение UI-режима Playwright
- Шаг 5 – Обнаружение визуальных регрессий с помощью Playwright
- Заключение
Прежде чем продолжить, убедитесь, что у вас установлена последняя версия Node.js, предпочтительно версия LTS.
Примечание редакции: если вы еще не очень хорошо знакомы с Playwright, то возможно вам будет интересна статья Сквозное тестирование с Playwright: полное руководство
Шаг 1 — Настройка React-демо проекта
Начните с клонирования репозитория TodoMVC React на ваш локальный компьютер:
git clone https://github.com/betterstack-community/react-todo-mvc
После клонирования перейдите в директорию проекта и установите необходимые зависимости:
cd react-todo-mvc npm install
Этот шаг гарантирует, что все необходимые библиотеки и инструменты будут доступны для сервера разработки. После установки вы можете запустить сервер с помощью команды:
npm run dev
Сервер инициализируется и начнет прослушивать порт 8080. Вывод будет похож на:
> todomvc-react@1.0.0 dev > webpack serve --open --config webpack.dev.js <i> [webpack-dev-server] Проект запущен на: <i> [webpack-dev-server] Loopback: http://localhost:8080/ <i> [webpack-dev-server] В вашей сети (IPv4): http://192.168.0.189:8080/ . . .
Чтобы убедиться, что приложение работает правильно, откройте в браузере http://localhost:8080. Вы увидите интерфейс TodoMVC. Попробуйте добавить несколько задач, чтобы убедиться, что приложение функционирует.
Теперь с помощью Playwright вы создадите тесты, которые проверят основные функции приложения, такие как возможность добавлять и управлять задачами. Эти тесты продемонстрируют мощь и простоту Playwright для автоматизированного тестирования браузера.
Перед тем как перейти к следующему шагу, остановите сервер разработки. Это можно сделать, нажав Ctrl-C в терминале, где запущен сервер. Сервер завершит работу корректно:
^C [webpack-dev-server] Gracefully shutting down. To force exit, press ^C again. Please wait...
Теперь, когда демо-проект настроен, можно интегрировать и настроить Playwright для написания и запуска сквозных тестов.
Шаг 2 — Настройка Playwright
В этом разделе вы установите Playwright в проект и настроите браузерные движки, необходимые для сквозного тестирования.
Начните с добавления Playwright в ваш проект. В корневой директории проекта выполните следующую команду:
npm init playwright@latest
Во время установки вам предложат настроить несколько параметров. Для нашего проекта выберите следующие параметры:
Initializing project in 'react-todo-mvc' ✔ Do you want to use TypeScript or JavaScript? · JavaScript ✔ Where to put your end-to-end tests? · tests ✔ Add a GitHub Actions workflow? (y/N) · false ✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) · true ✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo npx playwright install-deps')? (y/N) · true
После установки вы увидите сообщение о завершении, показывающее, что Playwright и его зависимости теперь являются частью вашего проекта:
. . . Рекомендуем начать с команды: npx playwright test И ознакомьтесь со следующими файлами: - ./tests/example.spec.js - Пример сквозного теста - ./tests-examples/demo-todo-app.spec.js - Сквозные тесты для Todo App - ./playwright.config.js - Конфигурация тестов Playwright
Теперь давайте настроим Playwright для нашего тестирования. Откройте файл playwright.config.js
, который был создан во время установки, в вашем текстовом редакторе:
code playwright.config.js
Вот как выглядит playwright.config.js
:
// @ts-check const { defineConfig, devices } = require('@playwright/test'); module.exports = defineConfig({ testDir: './tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'html', use: { baseURL: 'http://127.0.0.1:8081', trace: 'on-first-retry', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, ], webServer: { command: 'npm run playwright-server', url: 'http://127.0.0.1:8081', reuseExistingServer: !process.env.CI, }, });
Playwright предлагает множество параметров настройки тестов, но наиболее важные перечислены ниже:
- testDir: Указывает на директорию
./tests
, где будут находиться ваши тестовые файлы. - projects: Определяет браузерные среды для тестирования (Chromium, Firefox, WebKit).
- webServer: Позволяет запускать локальный сервер перед тестированием, что полезно в разработке.
- use.baseURL: Задает корневой URL вашего сервера, чтобы в тестах можно было использовать относительные пути вместо абсолютных.
Прежде чем продолжить, создайте скрипт для Playwright в вашем файле package.json
следующим образом:
"scripts": { "playwright-server": "webpack serve --port=8081 --config webpack.dev.js", },
Этот скрипт запустит сервер разработки на другом порту специально для тестирования Playwright.
Теперь Playwright настроен и готов к написанию первого тестового скрипта.
Шаг 3 — Написание первого теста
Playwright уже создал директорию tests
с примером теста. Для начала удалите этот пример:
rm tests/example.spec.js
Теперь создайте новый файл теста специально для вашего приложения To-do:
code tests/todo.spec.js
В этом новом файле теста вы напишете тест, который проверит начальное состояние приложения. Цель заключается в том, чтобы убедиться, что после загрузки нет ни одного элемента списка задач, а поле ввода находится в фокусе.
Напишите код для проверки этих условий:
const { test, expect } = require('@playwright/test'); test.describe('Initial state', () => { test('should be empty with focused input', async ({ page }) => { // Загрузка приложения TodoMVC await page.goto('/'); const todoList = page.getByTestId('todo-list'); // Убедитесь, что список не содержит элементов await expect(todoList).toBeEmpty(); const todoInput = page.getByTestId('text-input'); // Убедитесь, что поле ввода находится в фокусе await expect(todoInput).toBeFocused(); }); });
Функции test
и expect
Playwright помогают определить тест и выполнить проверки. Метод describe()
группирует связанные тесты и описывает, что охватывает данный набор тестов.
Внутри test.describe()
, функция test()
определяет конкретный тест для проверки пустого состояния списка задач и фокуса на поле ввода. Тест переходит на приложение TodoMVC по адресу http://localhost:8081, а затем использует локатор getByTestId()
для поиска элементов по атрибуту data-testid
.
Затем функция expect()
используется для проверки того, что список задач пуст, а поле ввода находится в фокусе.
Чтобы запустить тест, выполните следующую команду в терминале:
npx playwright test
Эта команда запускает сервер разработки и выполняет тесты в разных браузерах, как указано в playwright.config.js
. Все тесты должны пройти, что означает, что начальное состояние приложения работает как ожидалось во всех основных браузерах.
Output . . . Running 3 tests using 3 workers 3 passed (4.9s)
Чтобы открыть последний HTML отчет, выполните:
npx playwright show-report
После подтверждения начального состояния приложения в следующем разделе вы протестируете более сложные взаимодействия с пользователем. Также вы изучите, как режим UI Playwright поможет понять и отладить эти взаимодействия.
Шаг 4 — Изучение UI-режима Playwright
В этой части вы создадите тест, чтобы убедиться, что задачи можно успешно добавлять в приложение, и воспользуетесь UI-режимом Playwright для визуализации и отладки выполнения теста.
Сначала обновите файл todo.spec.js
, добавив новый тест:
. . . const TODO_ITEMS = ['save the world', 'go back in time', 'learn C']; test.describe('New Todo', () => { test('should allow me to add todo items', async ({ page }) => { await page.goto('/'); // создаем локатор для нового списка задач const todoList = page.getByTestId('todo-list'); const todoInput = page.getByTestId('text-input'); // Добавляем первую задачу await todoInput.fill(TODO_ITEMS[0]); await todoInput.press('Enter'); // Убедитесь, что в списке только одна задача await expect(page.getByTestId('todo-item-label')).toHaveText([ TODO_ITEMS[0], ]); // Добавляем вторую задачу await todoInput.fill(TODO_ITEMS[1]); await todoInput.press('Enter'); // Убедитесь, что в списке две задачи await expect(page.getByTestId('todo-item-label')).toHaveText([ TODO_ITEMS[0], TODO_ITEMS[1], ]); }); });
Этот тест проверяет, что пользователи могут добавлять элементы в список дел, а также, что список обновляется соответствующим образом.
Он начинается с загрузки приложения и выбора поля ввода для новых задач, используя его data-testid
, а затем выполняется поэтапно:
- Первый элемент из массива TODO_ITEMS вводится в поле ввода, и симулируется нажатие клавиши Enter.
- Затем проверяется, что в списке задач содержится только этот первый элемент.
- Аналогично вводится второй элемент из TODO_ITEMS.
- Снова проверяется список задач, чтобы убедиться, что теперь в нем содержатся как первый, так и второй элементы.
Чтобы наблюдать за выполнением теста, используйте команду:
npx playwright test -g 'New Todo' --ui
После выполнения этой команды откроется UI-режим Playwright. Этот инструмент позволяет визуально пошагово проходить тесты, исследовать DOM на разных этапах, просматривать временные шкалы выполнения тестов и анализировать действия, логи и ошибки в реальном времени. Этот режим значительно упрощает процесс отладки и улучшения тестов.
Когда UI-режим активирован, тест сначала будет на паузе. Чтобы продолжить выполнение, нажмите на значок Play рядом с заголовком теста. Тест должен успешно выполниться без ошибок.
На временной шкале в верхней части интерфейса вы можете увидеть процесс выполнения теста. При наведении курсора на любой участок шкалы появляется снимок экрана теста. Вы также можете выбрать интервал, чтобы фильтровать действия и логи только для этой части теста.
Вкладка Actions перечисляет все действия, выполненные в тесте, с указанием использованных локаторов и продолжительности выполнения. Вы можете щелкнуть по любому действию, чтобы увидеть изменения в приложении. Вкладки Before и After позволяют визуально сравнивать состояние приложения до и после выполнения действия.
Кроме того, можно исследовать DOM на любом этапе теста, нажав на значок внешней ссылки в верхнем правом углу снимка DOM. Откроется окно, в котором вы можете использовать DevTools браузера для более детального изучения и устранения проблем в скриптах.
Под снимком DOM доступны несколько вкладок с дополнительной информацией:
- Locator: Позволяет выбрать локаторы из снимка DOM и скопировать их в тестовый скрипт.
- Source: Показывает код для выделенного действия.
- Call: Отображает информацию о времени выполнения и деталях локатора.
- Log: Содержит внутренние логи Playwright.
- Errors: Показывает любые ошибки, возникшие во время теста.
- Console и Network: Отображают логи приложения и сетевые запросы.
- Attachments: Полезны для визуальных сравнений при регрессионном тестировании.
Используя эти функции, вы сможете эффективно отлаживать и понимать поведение ваших тестов Playwright, чтобы убедиться, что они корректно проверяют функциональность приложения.
Шаг 5 — Обнаружение визуальных регрессий с помощью Playwright
Тестирование визуальных регрессий — это процесс проверки пользовательского интерфейса (UI) приложения на предмет визуальных изменений, которые могли возникнуть после внесения изменений в код. Оно сравнивает текущий внешний вид элементов или страниц приложения с набором базовых изображений, созданных ранее, чтобы убедиться, что элементы интерфейса выглядят правильно в разных окружениях, браузерах или после изменений кода.
Playwright значительно упрощает проверку визуальных регрессий, следуя общему процессу:
- Сначала создается набор базовых изображений, представляющих ожидаемое состояние элементов интерфейса или страниц. Эти изображения служат отправной точкой для будущих сравнений.
- Затем во время выполнения теста захватывается текущее состояние интерфейса.
- Далее эти изображения сравниваются с эталоном. Любые расхождения отмечаются как возможные регрессии, которые могут быть вызваны изменениями в CSS, макете, обновлениями JavaScript или поведением браузера.
Playwright использует библиотеку pixelmatch для сравнения изображений на уровне пикселей. При первом выполнении теста визуальной регрессии создается и сохраняется эталонный снимок, который служит базовой точкой для последующих сравнений.
Чтобы увидеть это на практике, добавьте следующий тест в файл todo.spec.js
:
. . . test.describe('Visual comparison', () => { test('initial state', async ({ page }) => { await expect(page).toHaveScreenshot(); }); });
Этот тест использует метод toHaveScreenshot()
, чтобы захватить и сравнить текущее состояние страницы с ожидаемым базовым изображением.
Перед выполнением теста рекомендуется провести рефакторинг кода:
const { test, expect } = require('@playwright/test'); test.beforeEach(async ({ page }) => { await page.goto('/'); }); test.describe('Initial state', () => { test('should be empty with focused input', async ({ page }) => { const todoList = page.getByTestId('todo-list'); // дополнительные проверки }); }); const TODO_ITEMS = ['save the world', 'go back in time', 'learn C']; test.describe('New Todo', () => { test('should allow me to add todo items', async ({ page }) => { const todoList = page.getByTestId('todo-list'); // дополнительные проверки }); }); test.describe('Visual comparison', () => { test('initial state', async ({ page }) => { await expect(page).toHaveScreenshot(); }); });
Чтобы избежать повторения строки, которая переходит на корневой путь в каждом тесте, хук beforeEach()
гарантирует, что страница загружается перед выполнением каждого теста. Это помогает поддерживать чистую структуру тестов и обеспечивает соблюдение определённых условий перед выполнением каждого теста.
Теперь выполните набор тестов на визуальное сравнение, используя следующую команду:
npx playwright test -g 'Visual'
Изначально тест провалится из-за отсутствия базового изображения (так называемого “золотого файла”). Это ожидаемая ошибка, так как необходимо установить начальный базовый снимок.
npx playwright test -g 'Visual'
Output . . . 3 failed [chromium] › todo.spec.js:53:3 › Visual comparison › initial state ─────────────────────── [firefox] › todo.spec.js:53:3 › Visual comparison › initial state ──────────────────────── [webkit] › todo.spec.js:53:3 › Visual comparison › initial state ────────────────────────
После выполнения команды HTML-отчет откроется в браузере по умолчанию и покажет, что тесты не прошли во всех браузерах. Это произошло из-за отсутствия базовых изображений для сравнения. В отчете будет раздел «Скриншоты», где можно просмотреть сделанные снимки.
Эти начальные скриншоты сохраняются как эталонные изображения в вашем каталоге с тестами следующим образом:
tree tests
Output . . . tests ├── example.spec.js ├── todo.spec.js └── todo.spec.js-snapshots ├── Visual-comparison-initial-state-1-chromium-linux.png ├── Visual-comparison-initial-state-1-firefox-linux.png └── Visual-comparison-initial-state-1-webkit-linux.png
Имя каждого эталонного файла — это комбинация названия набора тестов, названия теста, браузера и платформы. Также можно задать имя скриншота вручную, используя аргумент в методе toHaveScreenshot()
:
await expect(page).toHaveScreenshot('todomvc-initial-state.png');
Это создаст файлы с именами, такими как:
todomvc-initial-state-chromium-linux.png todomvc-initial-state-firefox-linux.png todomvc-initial-state-webkit-linux.png
После создания базового скриншота все последующие тесты будут сравнивать текущее состояние интерфейса с этим эталоном.
Завершите работу HTML-отчета с помощью Ctrl-C, затем повторно выполните тест визуальной регрессии:
npx playwright test -g 'Visual'
Вы должны увидеть успешное выполнение тестов, что говорит об отсутствии визуальных расхождений:
Output . . . Running 3 tests using 3 workers 3 passed (5.3s) . . .
Чтобы продемонстрировать возможности отчетов Playwright для визуальной регрессии, внесите небольшое изменение в ваше приложение. Например, измените цвет заголовка в файле header.jsx
:
src/todo/components/header.jsx import { useCallback } from "react"; import { Input } from "./input"; import { ADD_ITEM } from "../constants"; export function Header({ dispatch }) { const addItem = useCallback((title) => dispatch({ type: ADD_ITEM, payload: { title } }), [dispatch]); return ( <header className="header" data-testid="header"> <h1 style={{color: "blue"}}>todos</h1> <Input onSubmit={addItem} label="New Todo Input" placeholder="What needs to be done?" /> </header> ); }
Это изменение меняет цвет текста заголовка на синий, имитируя типичное изменение в процессе разработки.
Выполните тест визуальной регрессии снова:
npx playwright test -g 'Visual'
На этот раз тест не пройдет, так как текущее состояние интерфейса будет отличаться от эталона:
Output . . . 3 failed [chromium] › todo.spec.js:53:3 › Visual comparison › initial state ─────────────────────── [firefox] › todo.spec.js:53:3 › Visual comparison › initial state ──────────────────────── [webkit] › todo.spec.js:53:3 › Visual comparison › initial state ────────────────────────
При сбое теста отчет автоматически откроется в вашем браузере и предоставит детальные сведения. Откройте любой элемент сбоя и прокрутите до раздела «Несоответствие изображений» для сравнения нового скриншота с эталоном. Вам будут предложены следующие вкладки:
- Diff выделяет затронутые элементы красным;
- Actual показывает текущее изображение;
- Expected показывает эталонное изображение;
- Side by side размещает эталонное и текущее изображения рядом;
- Slider позволяет интерактивно сравнивать с помощью ползунка.
При сбое теста возможны два варианта действий:
- Непреднамеренные изменения: Если визуальные изменения не задумывались, нужно исправить причину и повторить тесты.
- Преднамеренные изменения: Если изменения запланированы и должны стать новыми эталонами, обновите эталонные изображения командой:
npx playwright test -g 'Visual' --update-snapshots
Это перегенерирует базовые изображения, синхронизируя их с новым состоянием интерфейса:
Output . . . Running 3 tests using 3 workers [chromium] › todo.spec.js:53:3 › Visual comparison › initial state /home/ayo/dev/betterstack/demo/react-todo-mvc/tests/todo.spec.js-snapshots/Visual-comparison-initial-state-1-chromium-linux.png is re-generated, writing actual. [firefox] › todo.spec.js:53:3 › Visual comparison › initial state /home/ayo/dev/betterstack/demo/react-todo-mvc/tests/todo.spec.js-snapshots/Visual-comparison-initial-state-1-firefox-linux.png is re-generated, writing actual. [webkit] › todo.spec.js:53:3 › Visual comparison › initial state /home/ayo/dev/betterstack/demo/react-todo-mvc/tests/todo.spec.js-snapshots/Visual-comparison-initial-state-1-webkit-linux.png is re-generated, writing actual. 3 passed (5.1s) . . .
После обновления эталонных изображений тесты должны пройти, а обновленные скриншоты следует сохранить в системе контроля версий для использования в будущем.
Заключение
В этом руководстве вы научились создавать, выполнять и отлаживать сквозные тесты для React-приложения с Playwright. Мы также рассмотрели важность регрессионного тестирования для поддержания визуальной целостности интерфейса и показали, как эффективно реализовать такие тесты с помощью Playwright.
Перевод статьи «Playwright End-to-End Testing: A Step-by-Step Guide».