Анимации в интерфейсе — это не просто визуальные эффекты, а часть
логики взаимодействия. В случае использования библиотеки
mo.js тестирование осложняется асинхронностью,
зависимостью от времени и случайными параметрами (например,
delay, duration, easing,
random). Это требует особого подхода к проверке
корректности поведения.
Ключевые сложности:
Основная логика анимации (расчёт параметров, генерация конфигураций)
должна быть отделена от непосредственного вызова mo.js. Это
позволяет тестировать вычисления независимо от рендеринга.
Пример:
function getBurstConfig(x, y) {
return {
left: x,
top: y,
count: 10,
radius: { 0: 100 },
duration: 500
};
}
Тест проверяет:
test('генерация конфигурации burst', () => {
const config = getBurstConfig(50, 100);
expect(config.left).toBe(50);
expect(config.top).toBe(100);
expect(config.count).toBe(10);
});
Анимации в mo.js используют
requestAnimationFrame и внутренние таймеры. Для
тестирования используется подмена времени.
В среде тестирования (например, Jest):
jest.useFakeTimers();
Пример теста:
test('анимация запускается через delay', () => {
const burst = new mojs.Burst({ delay: 200 });
const spy = jest.spyOn(burst, 'play');
burst.replay();
jest.advanceTimersByTime(200);
expect(spy).toHaveBeenCalled();
});
Объекты анимации содержат внутреннее состояние, которое можно анализировать:
_progress — текущий прогресс_props — параметры анимации_isRunning — статус выполненияПример:
test('анимация меняет состояние при запуске', () => {
const tween = new mojs.Tween({ duration: 300 });
tween.play();
expect(tween._isRunning).toBe(true);
tween.stop();
expect(tween._isRunning).toBe(false);
});
Анимации часто используют события:
onStartonUpdateonCompleteПроверка вызова:
test('вызывается onComplete', () => {
const onCompl ete = jest.fn();
const tween = new mojs.Tween({
duration: 100,
onComplete
});
tween.play();
jest.advanceTimersByTime(100);
expect(onComplete).toHaveBeenCalled();
});
mo.js поддерживает генерацию случайных значений:
radius: { 0: 'rand(50, 100)' }
Для тестирования необходимо:
Пример замены:
Math.random = jest.fn(() => 0.5);
Это делает поведение детерминированным.
Анимации часто изменяют DOM:
transform, opacity)В тестовой среде DOM эмулируется через jsdom.
Пример:
test('элемент получает стиль transform', () => {
document.body.innerHTML = '<div id="el"></div>';
const el = document.getElementById('el');
const tween = new mojs.Tween({
duration: 100,
onUpdate: (progress) => {
el.style.transform = `scale(${progress})`;
}
});
tween.play();
jest.advanceTimersByTime(50);
expect(el.style.transform).toContain('scale');
});
test('класс добавляется при старте', () => {
const el = document.createElement('div');
const tween = new mojs.Tween({
onStart: () => el.classList.add('active')
});
tween.play();
expect(el.classList.contains('active')).toBe(true);
});
Для сложных конфигураций анимации удобно использовать снапшоты:
test('конфигурация burst соответствует ожиданиям', () => {
const burst = new mojs.Burst({
count: 5,
radius: { 0: 50 }
});
expect(burst._props).toMatchSnapshot();
});
Это позволяет отслеживать изменения конфигурации при рефакторинге.
Проверяет взаимодействие анимации с другими частями приложения.
Пример сценария:
test('клик запускает анимацию', () => {
document.body.innerHTML = '<button id="btn"></button>';
const btn = document.getElementById('btn');
const playSpy = jest.fn();
const burst = new mojs.Burst({});
burst.play = playSpy;
btn.addEventListener('click', () => burst.play());
btn.click();
expect(playSpy).toHaveBeenCalled();
});
Автоматические тесты не всегда могут гарантировать корректность визуального результата. Используются:
Подход:
Анимации могут влиять на FPS и производительность.
Методы тестирования:
Пример:
test('анимация выполняется за допустимое время', () => {
const start = performance.now();
const tween = new mojs.Tween({ duration: 100 });
tween.play();
jest.advanceTimersByTime(100);
const end = performance.now();
expect(end - start).toBeLessThan(200);
});
1. Анимация не запускается
play()delay2. Анимация не завершается
onCompleteduration3. Неправильные значения параметров
4. Рассинхронизация анимаций
Пример:
test('анимации синхронизированы', () => {
const a = new mojs.Tween({ duration: 100 });
const b = new mojs.Tween({ duration: 100 });
a.play();
b.play();
jest.advanceTimersByTime(100);
expect(a._progress).toBe(1);
expect(b._progress).toBe(1);
});
mo.js поддерживает Timeline для последовательностей.
const timeline = new mojs.Timeline();
timeline.add(tween1, tween2);
Тест:
test('timeline запускает все анимации', () => {
const t1 = new mojs.Tween({ duration: 100 });
const t2 = new mojs.Tween({ duration: 100 });
const timeline = new mojs.Timeline();
timeline.add(t1, t2);
timeline.play();
expect(t1._isRunning).toBe(true);
expect(t2._isRunning).toBe(true);
});
Грамотное тестирование анимаций в mo.js позволяет избежать нестабильного поведения интерфейса, упрощает рефакторинг и обеспечивает предсказуемость пользовательского опыта даже при сложных визуальных эффектах.