Snapshot testing

Snapshot testing — метод тестирования, направленный на проверку визуального состояния веб-приложения или структуры DOM в определённый момент времени. В контексте Protractor, который является инструментом для end-to-end тестирования Angular и других веб-приложений на JavaScript, snapshot testing позволяет фиксировать текущее состояние страницы и выявлять непреднамеренные изменения интерфейса при последующих тестах.


Основные принципы

Snapshot — это «снимок» состояния DOM, HTML-кода или визуального отображения компонента. Основные идеи snapshot testing:

  • Фиксация текущего состояния: сохраняется HTML или структура компонента в момент выполнения теста.
  • Сравнение с эталоном: при повторном прогоне теста текущее состояние сравнивается с ранее сохранённым.
  • Выявление регрессий: любые отличия сигнализируют о возможной ошибке или изменении интерфейса.

Snapshot testing не заменяет функциональное тестирование. Его задача — контроль визуальных и структурных изменений.


Подготовка окружения

Для работы с snapshot testing в Protractor чаще используют сторонние библиотеки, так как Protractor сам по себе не содержит встроенных средств для хранения и сравнения снимков. Наиболее популярные подходы:

  1. Использование jest-snapshot Jest можно интегрировать с Protractor для фиксации и проверки DOM.
  2. Сохранение HTML файлов вручную Проще всего сохранять browser.getPageSource() и сравнивать его с эталонной версией.
  3. Визуальные тесты через protractor-image-comparison Позволяет делать скриншоты страниц или элементов и сравнивать их с базовыми изображениями.

Сохранение и сравнение DOM

Для работы с DOM-снимками используется метод getPageSource() или извлечение конкретного элемента через element(by.css()).

Пример сохранения snapshot в файл:

const fs = require('fs');
const path = require('path');

it('должен сохранить snapshot страницы', async () => {
    await browser.get('https://example.com');
    const pageSource = await browser.getPageSource();
    const snapshotPath = path.join(__dirname, 'snapshots', 'homePage.html');
    fs.writeFileSync(snapshotPath, pageSource, 'utf-8');
});

Сравнение текущего состояния с эталонным snapshot:

const fs = require('fs');
const path = require('path');
const assert = require('assert');

it('должен сравнить snapshot страницы', async () => {
    await browser.get('https://example.com');
    const currentSource = await browser.getPageSource();
    const snapshotPath = path.join(__dirname, 'snapshots', 'homePage.html');
    const savedSnapshot = fs.readFileSync(snapshotPath, 'utf-8');
    assert.strictEqual(currentSource, savedSnapshot, 'DOM страницы изменился!');
});

Ключевой момент: при работе с динамическими элементами необходимо либо игнорировать динамические части, либо нормализовать их перед сравнением.


Визуальные сравнения

Иногда важно не только сравнивать HTML, но и проверять визуальное соответствие. Для этого используется protractor-image-comparison.

Пример настройки и использования:

const { ProtractorImageComparison } = require('protractor-image-comparison');

const imageComparison = new ProtractorImageComparison({
    baselineFolder: './baseline/',
    screenshotPath: './screenshots/',
    autoSaveBaseline: true
});

it('должен сделать визуальный snapshot элемента', async () => {
    await browser.get('https://example.com');
    const elementToCheck = element(by.css('.header'));
    const result = await imageComparison.checkElement(elementToCheck, 'header_snapshot');
    expect(result.misMatchPercentage).toBe(0);
});

Особенности:

  • baselineFolder — папка с эталонными изображениями.
  • screenshotPath — папка для текущих скриншотов.
  • misMatchPercentage — процент отличий; обычно 0 означает полное совпадение.

Интеграция с CI/CD

Snapshot testing особенно полезен при автоматическом прогоне тестов на CI/CD. При этом можно:

  • Сохранять snapshots в репозитории или отдельном артефакте.
  • Автоматически уведомлять о визуальных регрессиях.
  • Настраивать автоматическое обновление эталонных snapshot при осознанных изменениях интерфейса.

Рекомендации при работе с snapshot testing

  1. Минимизировать чувствительность к динамическим данным: использовать селекторы и методы, игнорирующие даты, идентификаторы и случайные значения.
  2. Разбивать страницы на компоненты: хранить snapshot по отдельным элементам, а не всю страницу целиком.
  3. Использовать визуальные проверки для ключевых элементов: кнопок, форм, модальных окон.
  4. Обновлять snapshot только при контролируемых изменениях: это предотвращает случайное принятие ошибок за эталон.

Snapshot testing в Protractor помогает выявлять регрессии на ранней стадии, контролировать визуальное и структурное состояние приложения, а также повышает надёжность end-to-end тестов.