E2E тестирование анимаций

E2E-тестирование анимационных интерфейсов опирается на устранение случайности, связанной с реальным временем, частотой кадров и аппаратными задержками. В системах на базе Popmotion ключевым источником недетерминированности выступают requestAnimationFrame, физические модели (spring), а также easing-функции, зависящие от времени.

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

Критические источники нестабильности:

  • реальная частота кадров браузера
  • асинхронные обновления DOM
  • таймеры и setTimeout
  • микрозадержки event loop
  • аппаратные различия окружений CI

Управление временем исполнения анимаций

Popmotion строит анимации на основе времени, а не кадров. Это позволяет в тестах заменять реальное время на контролируемое.

Основные стратегии:

  • подмена системных таймеров
  • фиксация временной шкалы
  • ручное продвижение времени
  • синхронизация requestAnimationFrame

В E2E-средах часто применяется искусственное ускорение времени через mocking API браузера.

Пример абстрактного управления временем:

clock.setSystemTime(0);
clock.tick(100);

Такой подход позволяет пошагово проверять состояние анимации без ожидания реального завершения переходов.


Popmotion: структура анимационного цикла

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

  • стартовое значение
  • прогресс времени
  • функция интерполяции
  • конечное значение

Анимационный цикл упрощённо выглядит как:

animate({
  from: 0,
  to: 100,
  duration: 500,
  onUpdate: v => element.style.transform = `translateX(${v}px)`
});

В тестовой среде проверяется не сам факт завершения, а промежуточные состояния на конкретных временных отметках.


Контроль RAF и синхронизация кадров

Ключевым элементом стабильного E2E является контроль requestAnimationFrame. В браузерных тестовых раннерах он часто переопределяется.

В таких инструментах, как Playwright и Cypress используется механизм управления виртуальными таймерами.

Типовая модель:

  • фиксация FPS или полного отключения RAF
  • принудительный вызов кадрового цикла
  • синхронное обновление DOM после каждого шага времени

Это устраняет расхождения между реальным рендерингом и тестовым исполнением.


Изоляция анимационной логики

Для стабильных E2E-сценариев анимации отделяются от бизнес-логики интерфейса.

Практика разделения:

  • слой представления (DOM)
  • слой анимации (Popmotion)
  • слой состояния приложения

Такой подход позволяет тестировать анимации без зависимости от внешних API и данных.

Пример изолированной анимации:

export const slide = (target) =>
  animate({
    from: 0,
    to: 300,
    duration: 400,
    onUpdate: v => target.style.left = `${v}px`
  });

В тестах проверяется только изменение left во времени.


Проверка промежуточных состояний

E2E-тестирование анимаций редко ограничивается финальным состоянием. Основная ценность заключается в контроле переходов.

Типовые точки проверки:

  • t = 0 ms (инициализация)
  • t = 25% duration
  • t = 50% duration
  • t = 100% duration

При использовании Popmotion состояние функции интерполяции детерминировано, поэтому проверка сводится к математическому соответствию ожидаемой кривой.


Easing-функции и их тестирование

Easing определяет характер движения и является частым источником визуальных регрессий.

Типы функций:

  • linear
  • ease-in
  • ease-out
  • spring-based curves

В Popmotion физические easing-функции часто основаны на spring-моделях, что добавляет нелинейность.

Тестирование easing сводится к:

  • проверке монотонности
  • проверке диапазона значений
  • сравнении с эталонной кривой

Spring-анимации и физическая модель

Spring-анимации в Popmotion используют параметры:

  • stiffness
  • damping
  • mass

Эти параметры формируют дифференциальное поведение системы.

В E2E-сценариях важно фиксировать:

  • отсутствие колебаний вне диапазона
  • затухание амплитуды
  • достижение равновесия

Проверка осуществляется через дискретизацию времени и анализ массива значений.


Визуальная регрессия анимаций

Классический подход E2E дополняется визуальной дифференциацией кадров.

Используются инструменты:

  • Playwright screenshot testing
  • Cypress snapshot testing
  • pixel diff comparison

Визуальная регрессия особенно важна для:

  • сложных easing-кривых
  • параллельных анимаций
  • stagger-анимаций

Алгоритм:

  • фиксированное состояние времени
  • рендер DOM
  • снятие скриншота
  • сравнение с эталоном

Синхронизация нескольких анимаций

Popmotion поддерживает композицию анимаций, включая последовательные и параллельные сценарии.

Проблемы E2E:

  • несогласованное завершение
  • расхождение таймингов
  • race conditions между анимациями

Типовая модель тестирования:

  • фиксация глобального времени
  • запуск группы анимаций
  • пошаговое продвижение времени
  • проверка состояния каждой сущности

Интеграция с тестовыми раннерами

Cypress предоставляет прямой доступ к управлению таймерами через cy.clock() и cy.tick(), что позволяет полностью контролировать анимационный цикл.

Playwright использует clock и advanceTime, обеспечивая более низкоуровневую синхронизацию с браузером.

Паттерны интеграции:

  • заморозка времени перед стартом теста
  • пошаговое продвижение кадров
  • синхронное ожидание завершения промисов анимации

Флейки-тесты и их устранение

Основные причины нестабильности:

  • нефиксированное время
  • параллельные обновления DOM
  • различия производительности CI
  • несинхронизированные RAF

Методы стабилизации:

  • полное отключение реального времени
  • фиксация FPS
  • минимизация асинхронности
  • явное ожидание завершения анимации

Поведенческая модель анимаций в тестах

Анимация в E2E рассматривается не как визуальный эффект, а как функция состояния:

state(t) → DOM snapshot

Такое представление позволяет:

  • формализовать поведение
  • предсказывать результат
  • сравнивать версии реализации

Popmotion в этом контексте выступает как детерминированный вычислитель временных функций, что делает возможным строгую проверку UI-переходов без зависимости от рендеринга браузера.