Визуальное регрессионное тестирование: бесплатно на Playwright

Визуальное регрессионное тестирование на ширинах телефонов с Playwright toHaveScreenshot: нестабильные расхождения и сравнение Percy, Applitools, BackstopJS.

Содержание

Визуальное регрессионное тестирование сравнивает скриншоты ваших страниц с утверждёнными эталонными изображениями и падает, когда пиксели меняются. На мобильных раскладках оно ловит то, что пропускают функциональные тесты: кнопку меню, вытолкнутую за экран шириной 360px, заголовок, который переносится на три строки, сетку карточек, неправильно сворачивающуюся на ширине планшета. Запускать его можно бесплатно через toHaveScreenshot() в Playwright на ширинах телефонов и планшетов, а потом решить, нужен ли платный сервис ради рабочего процесса проверки и кросс-браузерной отрисовки в облаке.

Как работает визуальное регрессионное тестирование

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

Инструменты отличаются именно сравнением. Попиксельное сравнение (Playwright, BackstopJS) считает изменившиеся пиксели и падает выше заданного вами порога. Applitools вместо строгого подсчёта пикселей сравнивает собственным Visual AI, а Percy и Chromatic — облачные сервисы с панелью проверки. Всем нужны стабильные страницы: если между двумя запусками меняются часы, реклама или анимация, тест падает без настоящей причины. Большая часть настройки ниже посвящена тому, чтобы убрать этот шум.

Визуальный регрессионный тест демо-страницы шириной 360 px: эталон, новый прогон, где длинное меню сдвигает кнопку Menu к краю, и изображение различий с изменёнными пикселями красным

Сравнение инструментов

Встроенная проверка Playwright закрывает бесплатный случай на своей инфраструктуре. По состоянию на октябрь 2026:

Инструмент Метод сравнения Стоимость Где сильнее
Playwright toHaveScreenshot Попиксельное сравнение, локально Бесплатно, открытый код Chromium, Firefox и WebKit в одном раннере, эталоны в вашем репозитории
BackstopJS Попиксельное сравнение, локально Бесплатно, открытый код Сценарии только в конфигурации (без кода тестов), HTML-отчёт, флаг --docker
Percy (BrowserStack) Облачное сравнение и интерфейс проверки Бесплатный тариф: 5000 скриншотов в месяц Облачная проверка и утверждение в разных браузерах и на разных ширинах
Chromatic Облачное сравнение на основе Storybook Бесплатный тариф: 5000 снимков в месяц, только Chrome Тестирование на уровне компонентов для проектов на Storybook
Applitools Eyes Visual AI Starter от $667 в месяц при годовой оплате; бесплатная пробная версия ИИ-сравнение, рассчитанное на то, чтобы пропускать шум отрисовки, который отмечает попиксельное сравнение; большие кросс-браузерные сетки

Percy считает каждую страницу в каждом браузере и на каждой ширине одним скриншотом, поэтому две страницы на трёх ширинах телефонов и планшетов в двух браузерах уже дают двенадцать. Цены и лимиты тарифов взяты со страниц цен каждого поставщика на 25 октября 2026 года и часто меняются.

Настройка визуальных регрессионных тестов на ширинах телефонов

Для этой настройки используется @playwright/test 1.64 (актуальная версия на 25 октября 2026). Нужны Node.js и сайт, который можно открыть с машины с тестами, локальный или развёрнутый.

  1. Установите Playwright и его браузеры:

    npm init playwright@latest
  2. Добавьте мобильные проекты в playwright.config.ts. Каждый дескриптор устройства задаёт viewport, pixel ratio, user agent и поддержку касаний и выбирает движок (iPhone 15 работает в WebKit, Pixel 7 — в Chromium).

    import { defineConfig, devices } from '@playwright/test';
    
    export default defineConfig({
      testDir: './visual',
      use: { baseURL: 'http://localhost:4321' },
      expect: {
        toHaveScreenshot: { maxDiffPixelRatio: 0.01 },
      },
      projects: [
        { name: 'pixel-7', use: { ...devices['Pixel 7'] } },
        { name: 'iphone-15', use: { ...devices['iPhone 15'] } },
        { name: 'tablet', use: { browserName: 'chromium', viewport: { width: 820, height: 1180 } } },
      ],
    });

    В Playwright 1.64 у дескриптора Pixel 7 viewport 412 × 839 при pixel ratio 2,625, а у iPhone 15 — 393 × 659 при 3. Значение maxDiffPixelRatio в 1% — стартовое, которое вы подбираете, а не стандарт.

  3. Напишите тест. Ограничьтесь страницами, раскладка которых важнее всего:

    // visual/pages.spec.ts
    import { test, expect } from '@playwright/test';
    
    const pages = ['/', '/pricing', '/blog'];
    
    for (const path of pages) {
      test(`layout ${path}`, async ({ page }) => {
        await page.goto(path);
        await page.evaluate(async () => { await document.fonts.ready; });
        await expect(page).toHaveScreenshot({
          fullPage: true,
          mask: [page.locator('[data-testid="live-date"]')],
        });
      });
    }
  4. Создайте эталоны и закоммитьте их:

    npx playwright test --update-snapshots

    Playwright сохраняет по одному PNG на каждый тест и проект, а в конце имени файла стоят имя проекта и платформа (например, ...-iphone-15-linux.png). Закоммитьте папки *-snapshots.

  5. Запускайте npx playwright test в каждом pull request. Неудачное сравнение роняет тест; откройте HTML-отчёт командой npx playwright show-report, чтобы посмотреть на сбой. Если изменение задумано, обновите эталоны через --update-snapshots и закоммитьте вместе с изменением кода.

Здесь помогают значения по умолчанию: toHaveScreenshot() ждёт, пока два последовательных скриншота совпадут, и только потом сравнивает, отключает CSS-анимации и переходы и скрывает текстовый курсор (документация Playwright API). Опция scale по умолчанию равна "css", один пиксель изображения на один CSS-пиксель, поэтому эталон для iPhone шириной 393 px, а не 1179, и сравнение остаётся быстрым.

Посмотрите на раскладку, прежде чем снимать эталоны

Эталон фиксирует, как страница выглядела в момент съёмки. Если уже на первом скриншоте телефонная раскладка сломана, каждый следующий запуск будет защищать эту ошибку. Прежде чем создавать эталоны, посмотрите на каждую страницу на тех ширинах, которые вы тестируете:

  1. Откройте страницу на ширине телефона. Mobile View Extension перезагружает вкладку с user agent, размером экрана и pixel ratio телефона и умеет показывать два устройства рядом, так что телефонную и планшетную раскладку одного URL можно проверить вместе. Работает на localhost.
  2. Прокрутите страницу целиком и проверьте навигацию, переносы в заголовках, таблицы и закреплённые (sticky) элементы.
  3. Исправьте найденное и выполните --update-snapshots.

Расширение отрисовывает страницу движком десктопного Chrome и управляется мышью, так что оно показывает раскладку, а не отрисовку в Safari и не поведение при касании. Проект WebKit в Playwright закрывает часть этого пробела, а настоящий iPhone закрывает остальное. Более широкий порядок ручных проверок описан в статье как тестировать адаптивный дизайн, а разовые снимки для тикетов — в статье как сделать мобильный скриншот сайта.

Как убрать нестабильные расхождения скриншотов

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

Причина Исправление
Другая ОС или сборка браузера Создавайте и сравнивайте эталоны на машине одного типа; в CI используйте закреплённый образ Docker под вашу версию Playwright, например mcr.microsoft.com/playwright:v1.64.0-noble
Веб-шрифты приходят поздно или подменяются Дожидайтесь document.fonts.ready; размещайте шрифты у себя, чтобы задержка CDN не меняла отрисовку
Даты, счётчики, реклама, встраиваемые блоки Закрывайте локаторы через mask или прячьте таблицей стилей из stylePath
Карусели и анимации на JavaScript Останавливайте их флагом только для тестов; toHaveScreenshot замораживает только CSS и Web Animations
Состояния hover Сначала уберите мышь: page.mouse.move(-1, -1)
Ленивые изображения на скриншотах всей страницы Прокрутите до низа или дождитесь изображений перед съёмкой
Шум сглаживания Поднимите threshold (по умолчанию 0,2) или задайте maxDiffPixels

Первая строка объясняет сбои, которые выглядят случайными. В документации Playwright предупреждают, что отрисовка может зависеть от ОС хоста, версии, настроек и железа, и по этой причине платформа входит в имя снимка: эталон, созданный на Mac (-darwin.png), не используется на Linux-раннере CI (-linux.png). Выберите одну среду для эталонов. Запуск npx playwright test --update-snapshots внутри того же образа Docker, который использует CI, убирает этот источник различий.

Файл stylePath — самое чистое место, чтобы скрывать шум во всех тестах сразу:

/* visual/screenshot.css */
iframe, [data-testid="cookie-banner"] { visibility: hidden; }
import path from 'node:path';

await expect(page).toHaveScreenshot({
  stylePath: path.join(__dirname, 'screenshot.css'),
});

Ту же опцию можно задать в expect.toHaveScreenshot в конфигурации, чтобы она применялась ко всем тестам.

Чего визуальные тесты не ловят

Сравнение скриншотов проверяет пиксели в тех движках, которые вы запускаете. Оно не проверяет, что кнопка работает, что зона касания достаточно велика и как страница ведёт себя в интерфейсе браузера и с клавиатурой настоящего телефона. WebKit в Playwright близок к Safari, но это не iOS Safari на iPhone. Держите функциональные тесты рядом с визуальными, а настоящие браузеры покрывайте по чек-листу кросс-браузерного тестирования.

Держите набор небольшим. Каждая страница, проект и состояние умножают число изображений на проверку. От трёх до десяти ключевых шаблонов (главная, список, страница с описанием, форма) на двух ширинах телефона и одной ширине планшета оставляют на проверку несколько десятков изображений за запуск. Это число — отправная точка для подбора (дизайн-решение), а не правило.

Частые вопросы

Бесплатно ли визуальное регрессионное тестирование?

Да, на инструментах с открытым кодом. toHaveScreenshot() в Playwright и BackstopJS запускаются локально и в вашем CI бесплатно. Платные сервисы вроде Percy, Chromatic и Applitools добавляют облачную отрисовку и панели проверки, а у Percy и Chromatic по состоянию на октябрь 2026 есть бесплатные тарифы на 5000 скриншотов или снимков в месяц.

Чем визуальное тестирование отличается от тестирования скриншотов?

Оба снимают скриншот и сравнивают его с утверждённым эталоном. Разница в сравнении: Playwright и BackstopJS считают изменившиеся пиксели, а Applitools использует Visual AI (см. таблицу инструментов выше).

Почему скриншоты Playwright падают в CI, но проходят локально?

Потому что эталоны созданы на другой операционной системе или сборке браузера. Playwright включает платформу в имя файла снимка, а шрифты и сглаживание различаются между macOS и Linux. Создавайте эталоны в том же образе Docker, который использует CI.

Как игнорировать динамическое содержимое в визуальных тестах?

Закройте элементы вроде дат и рекламы опцией mask или спрячьте их таблицей стилей из stylePath. Для целых областей, которые меняются, снимайте скриншот стабильного элемента, а не всей страницы.

Откройте следующий сайт в мобильном виде.

Установите расширение и запускайте превью устройств прямо в той вкладке, где уже работаете.