Сквозное тестирование c Playwright

Сквозное тестирование c Playwright

В этом руководстве вы изучите возможности Playwright, проведя сквозное (end-to-end) тестирование React-версии известного проекта TodoMVC.

Суть проекта TodoMVC – предоставление возможности разработчикам сравнить популярные JavaScript-фреймворки, анализируя код разных реализаций одного и того же приложения, созданных с помощью разных фреймворков. Не волнуйтесь, если вы не знакомы с React: основное внимание уделяется не его особенностям, а тестированию с помощью 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. Попробуйте добавить несколько задач, чтобы убедиться, что приложение функционирует.

Интерфейс 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();
  });
});

Функции Playwright test и expect помогают определить тест и выполнить проверки. Метод describe() группирует связанные тесты и описывает, что охватывает данный набор тестов.

Внутри test.describe() функция test() определяет конкретный тест для проверки пустого состояния списка задач и фокуса на поле ввода. Тест переходит на приложение TodoMVC по адресу http://localhost:8081, а затем использует локатор getByTestId() для поиска элементов по атрибуту data-testid.

Интерфейс TodoMVC. Снизу открыты инструменты разработчика, вкладка Inspector.

Затем с помощью функции 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). Затем выполняются следующие шаги:

  1. Первый элемент из массива TODO_ITEMS вводится в поле ввода и симулируется нажатие клавиши Enter.
  2. Проверяется, что в списке задач содержится только этот первый элемент.
  3. Аналогично вводится второй элемент из TODO_ITEMS.
  4. Снова проверяется список задач, чтобы убедиться, что теперь в нем содержатся как первый, так и второй элементы.

Чтобы наблюдать за выполнением теста, используйте команду:

npx playwright test -g 'New Todo' --ui

После выполнения этой команды откроется UI-режим Playwright. Этот инструмент позволяет визуально пошагово проходить тесты, исследовать DOM на разных этапах, просматривать временные шкалы выполнения тестов и анализировать действия, логи и ошибки в реальном времени. Этот режим значительно упрощает процесс отладки и улучшения тестов.

Пользовательский интерфейс Playwright. Красная стрелка указывает на кнопку Play.

Когда UI-режим активирован, тест сначала будет на паузе. Чтобы продолжить выполнение, нажмите на значок “Play” рядом с заголовком теста. Тест должен успешно выполниться.

Пользовательский интерфейс Playwright.

На временной шкале в верхней части интерфейса вы можете увидеть процесс выполнения теста. При наведении курсора на любой участок шкалы появляется снимок экрана теста. Вы также можете выбрать интервал, чтобы фильтровать действия и логи только для этой части теста.

Пользовательский интерфейс Playwright, временная шкала.

Вкладка Actions перечисляет все действия, выполненные в тесте, с указанием использованных локаторов и продолжительности выполнения. Вы можете щелкнуть по любому действию, чтобы увидеть изменения в приложении. Вкладки Before и After позволяют визуально сравнивать состояние приложения до и после выполнения действия.

Вкладки Before и After.

Кроме того, можно исследовать DOM на любом этапе теста, нажав на значок внешней ссылки в верхнем правом углу снимка DOM. Откроется окно, в котором вы можете использовать DevTools браузера для более детального изучения и устранения проблем в скриптах.

В браузере открыто приложение и инструменты разработчика

Под снимком DOM доступны несколько вкладок с дополнительной информацией:

  • Locator позволяет выбрать локаторы из снимка DOM и скопировать их в тестовый скрипт
  • Source показывает код для выделенного действия
  • Call отображает информацию о времени выполнения и деталях локатора
  • Log содержит внутренние логи Playwright
  • Errors показывает любые ошибки, возникшие во время теста
  • Console и Network отображают логи приложения и сетевые запросы
  • Attachments полезны для визуальных сравнений при регрессионном тестировании

Используя эти функции, вы сможете эффективно разбираться в поведении ваших тестов Playwright, чтобы убедиться, что они корректно проверяют функциональность приложения.

Шаг 5 — Обнаружение визуальных регрессий с помощью Playwright

Тестирование визуальных регрессий — это процесс проверки пользовательского интерфейса (UI) приложения на предмет визуальных изменений, которые могли возникнуть после внесения изменений в код. В ходе этого тестирования сравнивается текущий внешний вид элементов или страниц приложения с набором базовых изображений, созданных ранее, чтобы убедиться, что элементы интерфейса выглядят правильно в разных окружениях, браузерах или после изменений кода.

Playwright значительно упрощает проверку визуальных регрессий, следуя общему процессу:

  1. Сначала создается набор базовых изображений, представляющих ожидаемое состояние элементов интерфейса или страниц. Эти изображения служат отправной точкой для будущих сравнений.
  2. Затем во время выполнения теста захватывается текущее состояние интерфейса.
  3. Далее эти изображения сравниваются с эталоном. Любые расхождения отмечаются как возможные регрессии, которые могут быть вызваны изменениями в 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 ────────────────────────

При провале теста отчет автоматически откроется в вашем браузере и предоставит детальные сведения.

Отчет о проваленном тесте, режим Side by side.

Откройте любой элемент сбоя и прокрутите до раздела «Несоответствие изображений» для сравнения нового скриншота с эталоном. Вам будут предложены следующие вкладки:

  • 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».

    🔥 Какой была ваша первая зарплата в QA и как вы искали первую работу? 

    Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

    Читать в телеграм

    2 комментария к “Сквозное тестирование c Playwright”

    1. Пингбэк: Поиск элементов в Playwright

    2. Running 3 tests using 3 workers
      1) [chromium] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ──────

      Error: page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL
      Call log:
      – navigating to “/”, waiting until “load”

      4 | test(‘should be empty with focused input’, async ({ page }) => {
      5 | // Загрузка приложения TodoMVC
      > 6 | await page.goto(‘/’);
      | ^
      7 |
      8 | const todoList = page.getByTestId(‘todo-list’);
      9 |
      at /Users/aleksJS/projects/hexlet-playwright/tests/todo.spec.js:6:16

      Error Context: test-results/todo-Initial-state-should-be-empty-with-focused-input-chromium/error-context.md

      2) [webkit] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ────────

      Error: browserContext.newPage: Protocol error (Page.overrideSetting): Unknown setting: FixedBackgroundsPaintRelativeToDocument

      3) [firefox] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ───────

      Error: page.goto: Protocol error (Page.navigate): Invalid url: “/”
      Call log:
      – navigating to “/”, waiting until “load”

      4 | test(‘should be empty with focused input’, async ({ page }) => {
      5 | // Загрузка приложения TodoMVC
      > 6 | await page.goto(‘/’);
      | ^
      7 |
      8 | const todoList = page.getByTestId(‘todo-list’);
      9 |
      at /Users/aleksJS/projects/hexlet-playwright/tests/todo.spec.js:6:16

      Error Context: test-results/todo-Initial-state-should-be-empty-with-focused-input-firefox/error-context.md

      3 failed
      [chromium] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ───────
      [firefox] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ────────
      [webkit] › tests/todo.spec.js:4:3 › Initial state › should be empty with focused input ─────────

    Оставьте комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *