Попиксельное сравнение скриншотов ломается в тот момент, когда рендеринг шрифтов отличается между версиями ОС, анимация захвачена в промежуточном кадре или изменился timestamp. AI-инструменты визуального тестирования Percy и Applitools заменяют пиксельные диффы на семантическое сравнение: отличают настоящую регрессию вёрстки от шума рендеринга. Ниже разобрано как работает каждый подход, как обрабатывать динамический контент и когда стоимость AI-инструмента оправдана в сравнении со встроенными ассёртами скриншотов Playwright.
Проблема с попиксельным сравнением
// Традиционное сравнение скриншотов
test('homepage looks correct', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png'); // Падает на разнице в 1px
});Ломается из-за:
- Различий рендеринга шрифтов между ОС и версиями браузера
- Анимаций захваченных в разные кадры
- Динамического контента (временные метки, имена пользователей, рекламные блоки)
- Вариаций сглаживания
- Различий положения прокрутки
Выбор невелик: постоянные ложные падения или смягчённые пороговые значения которые пропускают реальные визуальные баги.
Как работает AI-визуальное тестирование
AI-сервисы визуального тестирования используют компьютерное зрение и машинное обучение:
1. Понимают вёрстку: знают что кнопка это кнопка, а не просто пиксели
2. Игнорируют нерелевантные различия: вариации рендеринга текста, незначительные отступы
3. Помечают значимые изменения: сдвиги вёрстки, отсутствующие элементы, изменения цвета, наложения
4. Группируют похожие падения: 50 тестов показывающих один баг становятся одной сгруппированной проблемой
AI обучен на тысячах реальных изменений UI, различая баги от шума рендеринга.
Percy (BrowserStack)
Percy это наиболее устоявшийся AI-инструмент визуального тестирования, приобретённый BrowserStack.
Настройка с Playwright
npm install --save-dev @percy/cli @percy/playwright// tests/visual.spec.ts
import { test } from '@playwright/test';
import percySnapshot from '@percy/playwright';
test('homepage visual', async ({ page }) => {
await page.goto('/');
await percySnapshot(page, 'Homepage');
});
test('login page visual', async ({ page }) => {
await page.goto('/login');
await percySnapshot(page, 'Login Page');
});
test('dashboard after login', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', 'user@test.com');
await page.fill('[data-testid="password"]', 'ValidPass1');
await page.click('[data-testid="submit"]');
await page.waitForURL('/dashboard');
await percySnapshot(page, 'Dashboard - Authenticated');
});Запуск Percy
# Установи Percy токен (из app.percy.io)
PERCY_TOKEN=your_token npx percy exec -- npx playwright testПри первом запуске Percy создаёт базовые скриншоты. Последующие запуски сравниваются с базой: AI Percy отмечает реальные визуальные изменения для проверки человеком.
Интеграция с CI
# .github/workflows/visual-tests.yml
- name: Run Percy visual tests
run: npx percy exec -- npx playwright test tests/visual.spec.ts
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}Percy публикует результаты как проверку PR: визуальные диффы появляются прямо в GitHub pull request.
Applitools Eyes
Applitools использует движок «Visual AI», который позиционируется как более точный по сравнению с пиксельным сравнением. Поддерживает адаптивное тестирование и сравнение на уровне компонентов.
npm install --save-dev @applitools/eyes-playwrightimport { test } from '@playwright/test';
import { Eyes, Target, Configuration } from '@applitools/eyes-playwright';
test('visual regression', async ({ page }) => {
const eyes = new Eyes();
const configuration = new Configuration();
configuration.setApiKey(process.env.APPLITOOLS_API_KEY!);
eyes.setConfiguration(configuration);
await eyes.open(page, 'My App', 'Homepage Test');
await page.goto('/');
await eyes.check('Homepage', Target.window().fully());
await page.goto('/products');
await eyes.check('Products Page', Target.window().fully());
await eyes.close();
});Ultrafast Grid
Ключевая функция Applitools: Ultrafast Grid рендерит снимок DOM в нескольких браузерах и вьюпортах одновременно, без запуска браузеров на твоей машине:
import { VisualGridRunner, BrowserType, DeviceName, ScreenOrientation } from '@applitools/eyes-playwright';
const runner = new VisualGridRunner({ testConcurrency: 5 });
const configuration = new Configuration();
configuration.addBrowser(1280, 800, BrowserType.CHROME);
configuration.addBrowser(1440, 900, BrowserType.FIREFOX);
configuration.addDeviceEmulation(DeviceName.iPhone_12, ScreenOrientation.PORTRAIT);
configuration.addDeviceEmulation(DeviceName.iPad_Pro, ScreenOrientation.LANDSCAPE);Один запуск Playwright-тестов, визуальные результаты для 4 конфигураций браузер/устройство.
Встроенное сравнение скриншотов Playwright
В Playwright есть базовое визуальное сравнение без AI:
// Встроенное: пиксельное сравнение с настраиваемым порогом
test('homepage screenshot', async ({ page }) => {
await page.goto('/');
// Допускаем до 1% разницы пикселей
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixelRatio: 0.01,
});
// Или устанавливаем абсолютное количество пикселей
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixels: 50,
});
});// Маскируем динамический контент
await expect(page).toHaveScreenshot('homepage.png', {
mask: [
page.getByTestId('timestamp'),
page.getByTestId('user-avatar'),
page.getByTestId('ad-banner'),
],
});Обработка динамического контента
Главный вызов в визуальном тестировании: контент который меняется в штатном режиме.
Маскирование динамических элементов
// Percy
await percySnapshot(page, 'Dashboard', {
percyCSS: `
[data-testid="timestamp"] { visibility: hidden; }
[data-testid="user-avatar"] { filter: blur(10px); }
`,
});
// Встроенный Playwright
await expect(page).toHaveScreenshot({
mask: [
page.locator('[data-testid="timestamp"]'),
page.locator('.ad-container'),
],
});Ожидание стабильного состояния
test('chart visual test', async ({ page }) => {
await page.goto('/analytics');
// Ждём завершения анимаций
await page.waitForLoadState('networkidle');
await page.waitForTimeout(500); // Буфер для CSS-переходов
// Ждём конкретный элемент означающий загрузку данных
await page.waitForSelector('[data-testid="chart-loaded"]');
await percySnapshot(page, 'Analytics Dashboard');
});Заморозка времени
// Замораживаем Date чтобы timestamps не менялись между запусками
await page.addInitScript(() => {
const fixedDate = new Date('2026-01-15T12:00:00Z');
Date.now = () => fixedDate.getTime();
Date = class extends Date {
constructor(...args) {
if (args.length === 0) {
super(fixedDate.getTime());
} else {
super(...args);
}
}
};
});Визуальное тестирование компонентов
Вместо скриншотов целых страниц: тестируй отдельные компоненты.
test('button variants visual test', async ({ page }) => {
await page.goto('/storybook/button');
// Тестируем каждый вариант кнопки
const variants = ['primary', 'secondary', 'danger', 'ghost'];
for (const variant of variants) {
await page.click(`[data-story="${variant}"]`);
await percySnapshot(page, `Button - ${variant}`);
}
});Тестирование компонентов устойчивее, чем тестирование целых страниц: меньше движущихся частей, легче изолировать что изменилось.
Организация рабочего процесса визуального тестирования
1. Создание базовых скриншотов
Первый запуск создаёт базовые скриншоты. Просматривай их внимательно: «одобряй» только корректные визуальные состояния.
2. Рабочий процесс PR
- Разработчик вносит изменения
- CI запускает визуальные тесты
- Диффы публикуются в PR
- QA или разработчик просматривает диффы
- Одобряет ожидаемые изменения (новая функция выглядит правильно), отклоняет неожиданные (баг)
3. Обновление базовых скриншотов
При намеренном изменении UI нужно обновить базу. Для Percy: одобри диффы в дашборде Percy. Для Playwright: запусти с флагом --update-snapshots.
npx playwright test --update-snapshotsЗакоммить обновлённые скриншоты вместе с PR.
Сравнение стоимости
| Инструмент | Бесплатный уровень | Платный |
|------------|-------------------|---------|
| Playwright (встроенный) | Бесплатно | Бесплатно |
| Percy | 5 000 скриншотов/мес | от $99/мес |
| Applitools | Ограниченный trial | По запросу |
| Chromatic | 5 000 снимков/мес | от $149/мес |
Для небольших проектов: встроенный Playwright с маскированием и настройкой порогов. Для команд с частыми релизами: Percy или Applitools; AI-ревью диффов сэкономит часы ручного сравнения.
Итог
| Подход | Точность | Стоимость | Лучше всего для |
|--------|----------|-----------|-----------------|
| Playwright (встроенный) | Попиксельный | Бесплатно | Статичные страницы, контролируемая среда |
| Percy | AI-powered | от $99/мес | Кросс-браузерное, командный ревью |
| Applitools | Visual AI + grid | По запросу | Enterprise, несколько браузеров |
Ключевые принципы:
- Маскируй динамический контент (временные метки, реклама, аватары)
- Жди стабильного состояния перед скриншотом
- Просматривай базовые скриншоты внимательно перед одобрением
- Группируй визуальные тесты по странице или компоненту для удобства ревью
AI-визуальное тестирование не устраняет ложные срабатывания полностью: оно резко сокращает их. Диффы которые доходят до стадии ревью гораздо чаще оказываются реальными проблемами.
→ See also: Визуальное регрессионное тестирование с Playwright: toHaveScreenshot без Applitools | Assertions в Playwright: полное руководство | Кросс-браузерное тестирование с Playwright: Chrome, Firefox, Safari