/
githubmirror
/
anime
Обзор
Документация
Войти
/
githubmirror
/
anime
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/suites/controls.test.js
1 078 строк
37 KB
Julian Garnier
4.5.0
22 июн 2026, 17:32
22 июн 2026, 17:32
34f4179
Код
Авторство
О чём код?
import { expect, getChildAtIndex, forEachChildren, } from '../utils.js'; import { animate, createTimeline, createTimer, utils, } from '../../dist/modules/index.js'; import { minValue, } from '../../dist/modules/core/consts.js'; suite('Controls', () => { test('Alternate the direction of an animation', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 50, onUpdate: self => { if (self.currentTime >= 100 * .75 && !hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.below(timeStamp); resolve(); }, 33); } }, }); }); test('Alternate the direction of a reversed animation', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 50, reversed: true, onUpdate: self => { if (!hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.above(timeStamp); resolve(); }, 33); } }, }); }); test('Alternate the direction of a looped animation', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 50, loop: 3, onUpdate: self => { if (self.currentTime >= (100 * 2.5) && !hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.below(timeStamp); expect(self.currentIteration).to.equal(1); resolve(); }, 33); } }, }); }); test('Alternate the direction of a looped alternate animation', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 50, loop: 3, alternate: true, onUpdate: self => { if (self.currentTime >= (100 * 2.5) && !hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.below(timeStamp); expect(self.currentIteration).to.equal(1); resolve(); }, 33); } }, }); }); test('Alternate the direction of a looped alternate reversed animation with odd iteration count', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 50, loop: 3, alternate: true, reversed: true, onUpdate: self => { if (self.currentTime >= (100 * 2.5) && !hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.below(timeStamp); expect(self.currentIteration).to.equal(1); resolve(); }, 33); } }, }); }); test('Alternate the direction of a looped alternate reversed animation with even iteration count', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); let hasReversed = false; animate($target, { translateX: 100, duration: 100, delay: 100, loop: 2, alternate: true, reversed: true, onUpdate: self => { if (self.currentTime >= (100 * 1.5) && !hasReversed) { hasReversed = true; const timeStamp = self.currentTime; self.alternate(); setTimeout(() => { expect(self.currentTime).to.be.above(timeStamp); expect(self.currentIteration).to.equal(1); resolve(); }, 40); } }, }); }); test('Complete a timer', () => { const timer1 = createTimer({ duration: 1000 }); timer1.complete(); expect(timer1._cancelled).to.equal(1); expect(timer1.paused).to.equal(true); expect(timer1.currentTime).to.equal(1000); }); test('Complete an animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.style.height = '100px'; const animation1 = animate($target, { width: 32, height: 200, ease: 'linear', }); animation1.complete(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); expect(animation1.currentTime).to.equal(1000); expect($target.getAttribute('style')).to.equal('height: 200px; width: 32px;'); }); test('Complete a timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.style.height = '100px'; $target.style.transform = 'translateY(100px)'; const tl = createTimeline({defaults: {ease: 'linear'}}) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); tl.complete(); expect(tl._cancelled).to.equal(1); expect(getChildAtIndex(tl, 0)._cancelled).to.equal(1); expect(getChildAtIndex(tl, 1)._cancelled).to.equal(1); expect(tl.paused).to.equal(true); expect(getChildAtIndex(tl, 0).paused).to.equal(true); expect(getChildAtIndex(tl, 1).paused).to.equal(true); expect(tl.currentTime).to.equal(tl.duration); expect(getChildAtIndex(tl, 0).currentTime).to.equal(getChildAtIndex(tl, 0).duration); expect(getChildAtIndex(tl, 1).currentTime).to.equal(getChildAtIndex(tl, 1).duration); expect($target.getAttribute('style')).to.equal('height: 400px; transform: translate(200px, 200px); width: 64px;'); }); test('Cancel a timer', () => { const timer1 = createTimer({ duration: 1000 }); timer1.seek(500).cancel(); expect(timer1._cancelled).to.equal(1); expect(timer1.paused).to.equal(true); }); test('Cancel an animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.style.height = '100px'; const animation1 = animate($target, { width: 32, height: 200, ease: 'linear', }); animation1.seek(500).cancel(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); expect($target.getAttribute('style')).to.equal('height: 150px; width: 24px;'); }); test('Cancel a timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.style.height = '100px'; $target.style.transform = 'translateY(100px)'; const tl = createTimeline({defaults: {ease: 'linear'}}) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); tl.seek(1000); tl.cancel(); expect(tl._cancelled).to.equal(1); expect(getChildAtIndex(tl, 0)._cancelled).to.equal(1); expect(getChildAtIndex(tl, 1)._cancelled).to.equal(1); expect(tl.paused).to.equal(true); expect(getChildAtIndex(tl, 0).paused).to.equal(true); expect(getChildAtIndex(tl, 1).paused).to.equal(true); expect($target.getAttribute('style')).to.equal('height: 200px; transform: translate(0px, 100px); width: 32px;'); }); test('Revert a timeline', () => { const timer1 = createTimer({ duration: 1000 }); timer1.seek(500); timer1.revert(); expect(timer1._cancelled).to.equal(1); expect(timer1.paused).to.equal(true); }); test('Revert an animation with CSS properties', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { width: 200, height: 200, }); animation1.seek(500); animation1.revert(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); expect($target.getAttribute('style')).to.equal(null); }); test('Revert an animation with Transforms properties', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { translateX: 200, translateY: 200, }); animation1.seek(500); animation1.revert(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); expect($target.getAttribute('style')).to.equal(null); }); test('Revert an animation with CSS properties with existing inline styles and clean newly added inline styles', () => { const targets = document.querySelectorAll('.target-class'); const cssText = []; targets.forEach(($target, i) => { const targetStyle = /** @type {HTMLElement} */($target).style; targetStyle.borderRadius = `${i * 10}%`; cssText[i] = targetStyle.cssText; }); const animation1 = animate(targets, { borderRadius: '50%', width: 200, height: 200, }); animation1.seek(500); animation1.revert(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); targets.forEach(($target, i) => { const targetStyle = /** @type {HTMLElement} */($target).style; expect(targetStyle.cssText).to.equal(cssText[i]); }); }); test('Revert an animation with transform properties with existing inline styles and clean newly added inline styles', () => { const targets = document.querySelectorAll('.target-class'); const cssText = []; targets.forEach(($target, i) => { const targetStyle = /** @type {HTMLElement} */($target).style; targetStyle.borderRadius = `${i * 10}%`; cssText[i] = targetStyle.cssText; }); const animation1 = animate(targets, { translateX: 200, translateY: 200, }); animation1.seek(500); animation1.revert(); expect(animation1._cancelled).to.equal(1); expect(animation1.paused).to.equal(true); targets.forEach(($target, i) => { const targetStyle = /** @type {HTMLElement} */($target).style; expect(targetStyle.cssText).to.equal(cssText[i]); }); }); test('Revert a timeline and and clean inline styles', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline({defaults: {ease: 'linear'}}) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); tl.seek(1500); tl.revert(); expect(tl._cancelled).to.equal(1); expect(getChildAtIndex(tl, 0)._cancelled).to.equal(1); expect(getChildAtIndex(tl, 1)._cancelled).to.equal(1); expect(tl.paused).to.equal(true); expect(getChildAtIndex(tl, 0).paused).to.equal(true); expect(getChildAtIndex(tl, 1).paused).to.equal(true); expect($target.getAttribute('style')).to.equal(null); }); test('Revert a timeline with existing inline styles and clean newly added inline styles', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.style.height = '100px'; $target.style.transform = 'translateY(100px)'; const tl = createTimeline({defaults: {ease: 'linear'}}) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); tl.seek(1500); tl.revert(); expect(tl._cancelled).to.equal(1); expect(getChildAtIndex(tl, 0)._cancelled).to.equal(1); expect(getChildAtIndex(tl, 1)._cancelled).to.equal(1); expect(tl.paused).to.equal(true); expect(getChildAtIndex(tl, 0).paused).to.equal(true); expect(getChildAtIndex(tl, 1).paused).to.equal(true); expect($target.getAttribute('style')).to.equal('transform: translateY(100px); height: 100px;'); }); test('Reset a playing animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { translateX: 200, translateY: 200, autoplay: false, duration: 1000, loop: 1 }); expect(animation1.currentTime).to.equal(0); // expect(animation1.progress).to.equal(0); expect(animation1.paused).to.equal(true); expect(animation1.began).to.equal(false); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(0); animation1.seek(1500); animation1.resume(); expect(animation1.currentTime).to.equal(1500); // expect(animation1.progress).to.equal(.75); expect(animation1.paused).to.equal(false); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(1); animation1.pause(); animation1.seek(2000); expect(animation1.currentTime).to.equal(2000); // expect(animation1.progress).to.equal(1); expect(animation1.paused).to.equal(true); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(true); expect(animation1.currentIteration).to.equal(1); animation1.seek(500); animation1.resume(); animation1.reset(); expect(animation1.currentTime).to.equal(0); // expect(animation1.progress).to.equal(0); expect(animation1.paused).to.equal(true); expect(animation1.began).to.equal(false); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(0); animation1.pause(); }); test('Reset a playing timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline({ autoplay: false, duration: 1000, loop: 1 }) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); expect(tl.currentTime).to.equal(0); expect(tl.progress).to.equal(0); expect(tl.paused).to.equal(true); expect(tl.began).to.equal(false); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(0); forEachChildren(tl, child => { expect(child.currentTime).to.equal(0); expect(child.progress).to.equal(0); expect(child.paused).to.equal(true); expect(child.began).to.equal(false); expect(child.completed).to.equal(false); expect(child.currentIteration).to.equal(0); }); tl.seek(3000); tl.resume(); expect(tl.currentTime).to.equal(3000); expect(tl.progress).to.equal(.75); expect(tl.paused).to.equal(false); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(1); tl.pause(); tl.seek(4000); expect(tl.currentTime).to.equal(4000); expect(tl.progress).to.equal(1); expect(tl.paused).to.equal(true); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(true); expect(tl.currentIteration).to.equal(1); forEachChildren(tl, child => { expect(child.paused).to.equal(true); expect(child.began).to.equal(true); expect(child.completed).to.equal(true); }); tl.seek(500); tl.resume(); tl.reset(); expect(tl.currentTime).to.equal(0); expect(tl.progress).to.equal(0); expect(tl.paused).to.equal(true); expect(tl.began).to.equal(false); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(0); forEachChildren(tl, child => { expect(child.currentTime).to.equal(0); expect(child.progress).to.equal(0); expect(child.paused).to.equal(true); expect(child.began).to.equal(false); expect(child.completed).to.equal(false); expect(child.currentIteration).to.equal(0); }); tl.pause(); }); test('Reseting an animation should set its values back to their initial states', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const ogY = utils.get($target, 'y'); animate($target, { y: -100, autoplay: false, duration: 1000, loop: 1, }) .reset(); const newY = utils.get($target, 'y'); expect(newY).to.equal(ogY); }); test('Reseting a timeline should set its values back to their initial states', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const ogY = utils.get($target, 'y'); const tl = createTimeline({ autoplay: false }) .add($target, { y: -100, duration: 500 }, 1000) .add($target, { y: 100, duration: 500 }, 2000) .reset(); const newY = utils.get($target, 'y'); expect(newY).to.equal(ogY); }); test('Reset a cancelled animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { translateX: 200, translateY: 200, duration: 1000, loop: 1 }); expect(animation1._cancelled).to.equal(0); expect(animation1.currentTime).to.equal(0); // expect(animation1.progress).to.equal(0); expect(animation1.paused).to.equal(false); expect(animation1.began).to.equal(false); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(0); animation1.seek(1500); animation1.cancel(); expect(animation1._cancelled).to.equal(1); expect(animation1.currentTime).to.equal(1500); // expect(animation1.progress).to.equal(.75); expect(animation1.paused).to.equal(true); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(1); animation1.reset(); expect(animation1._cancelled).to.equal(0); expect(animation1.currentTime).to.equal(0); // expect(animation1.progress).to.equal(0); expect(animation1.paused).to.equal(true); expect(animation1.began).to.equal(false); expect(animation1.completed).to.equal(false); expect(animation1.currentIteration).to.equal(0); animation1.pause(); }); test('Reset a cancelled timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline({ duration: 1000, loop: 1 }) .add($target, { width: 32, height: 200, }) .add($target, { width: 64, height: 400, translateX: 200, translateY: 200, }); expect(tl._cancelled).to.equal(0); expect(tl.currentTime).to.equal(0); expect(tl.progress).to.equal(0); expect(tl.paused).to.equal(false); expect(tl.began).to.equal(false); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(0); forEachChildren(tl, child => { expect(child._cancelled).to.equal(0); expect(child.currentTime).to.equal(0); expect(child.progress).to.equal(0); expect(child.paused).to.equal(true); expect(child.began).to.equal(false); expect(child.completed).to.equal(false); }); tl.seek(3000); tl.cancel(); expect(tl._cancelled).to.equal(1); expect(tl.currentTime).to.equal(3000); expect(tl.progress).to.equal(.75); expect(tl.paused).to.equal(true); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(1); forEachChildren(tl, child => { expect(child._cancelled).to.equal(1); expect(child.paused).to.equal(true); }); tl.reset(); expect(tl._cancelled).to.equal(0); expect(tl.currentTime).to.equal(0); expect(tl.progress).to.equal(0); expect(tl.paused).to.equal(true); expect(tl.began).to.equal(false); expect(tl.completed).to.equal(false); expect(tl.currentIteration).to.equal(0); forEachChildren(tl, child => { expect(child._cancelled).to.equal(0); expect(child.currentTime).to.equal(0); expect(child.progress).to.equal(0); expect(child.paused).to.equal(true); expect(child.began).to.equal(false); expect(child.completed).to.equal(false); }); tl.pause(); }); test('Refresh an animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-width', '128px'); const animation1 = animate($target, { width: $el => $el.dataset.width, duration: 100, autoplay: false }); animation1.seek(100); expect($target.style.width).to.equal('128px'); $target.setAttribute('data-width', '256px'); animation1.refresh().restart().seek(100); expect($target.style.width).to.equal('256px'); }); test('Refresh an animation with relative values', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { x: '+=50', rotate: () => '+=10', duration: 100, autoplay: false }); animation1.seek(100); expect(utils.get($target, 'x')).to.equal('50px'); expect(utils.get($target, 'rotate')).to.equal('10deg'); animation1.refresh().restart().seek(100); // Only function based value should refresh expect(utils.get($target, 'x')).to.equal('50px'); expect(utils.get($target, 'rotate')).to.equal('20deg'); }); test('Refresh an animation from value', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-width', '200px'); const animation1 = animate($target, { width: [() => $target.dataset.width, '400px'], duration: 100, ease: 'linear', autoplay: false }); animation1.seek(0); expect($target.style.width).to.equal('200px'); animation1.seek(50); expect($target.style.width).to.equal('300px'); animation1.seek(100); expect($target.style.width).to.equal('400px'); $target.setAttribute('data-width', '100px'); animation1.refresh().restart().seek(0); expect($target.style.width).to.equal('100px'); animation1.seek(50); expect($target.style.width).to.equal('250px'); animation1.seek(100); expect($target.style.width).to.equal('400px'); }); test('Refresh an animation from value in object form', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-width', '200px'); const animation1 = animate($target, { width: { from: () => $target.dataset.width, to: '400px' }, duration: 100, ease: 'linear', autoplay: false }); animation1.seek(0); expect($target.style.width).to.equal('200px'); animation1.seek(100); expect($target.style.width).to.equal('400px'); $target.setAttribute('data-width', '100px'); animation1.refresh().restart().seek(0); expect($target.style.width).to.equal('100px'); animation1.seek(50); expect($target.style.width).to.equal('250px'); animation1.seek(100); expect($target.style.width).to.equal('400px'); }); test('Refresh an animation from value with unit conversion', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-width', '50vw'); const animation1 = animate($target, { width: [() => $target.dataset.width, '400px'], duration: 100, ease: 'linear', autoplay: false }); const initialFromWidth = parseFloat($target.style.width); animation1.seek(100); expect($target.style.width).to.equal('400px'); $target.setAttribute('data-width', '25vw'); animation1.refresh().restart().seek(0); const refreshedFromWidth = parseFloat($target.style.width); // After refresh, from value should be recalculated (25vw converted to px) expect(refreshedFromWidth).to.be.below(initialFromWidth); animation1.seek(100); expect($target.style.width).to.equal('400px'); }); test('Refresh an animation with from / to values', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-from', '100px'); $target.setAttribute('data-to', '200px'); const animation1 = animate($target, { width: [() => $target.dataset.from, () => $target.dataset.to], duration: 100, ease: 'linear', autoplay: false }); animation1.seek(0); expect($target.style.width).to.equal('100px'); animation1.seek(100); expect($target.style.width).to.equal('200px'); $target.setAttribute('data-from', '50px'); $target.setAttribute('data-to', '150px'); animation1.refresh().restart().seek(0); expect($target.style.width).to.equal('50px'); animation1.seek(50); expect($target.style.width).to.equal('100px'); animation1.seek(100); expect($target.style.width).to.equal('150px'); }); test('Refresh an animation with from, to, unit conversion and relative operator', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-from', '10vw'); const animation1 = animate($target, { width: [() => $target.dataset.from, () => '+=100'], duration: 100, ease: 'linear', autoplay: false }); animation1.seek(0); const initialFromWidth = parseFloat($target.style.width); animation1.seek(100); const initialToWidth = parseFloat($target.style.width); // To value should be from + 100px expect(initialToWidth).to.equal(initialFromWidth + 100); $target.setAttribute('data-from', '20vw'); animation1.refresh().restart().seek(0); const refreshedFromWidth = parseFloat($target.style.width); // After refresh, from value should be larger (20vw > 10vw) expect(refreshedFromWidth).to.be.above(initialFromWidth); animation1.seek(100); const refreshedToWidth = parseFloat($target.style.width); // To value should still be from + 100px (relative operator applied to new from) expect(refreshedToWidth).to.equal(refreshedFromWidth + 100); }); test('Refresh a timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); $target.setAttribute('data-width', '128px'); const tl = createTimeline(); tl.add($target, { width: $el => $el.dataset.width, duration: 100, autoplay: false }).add({ duration: 100 }); tl.seek(200); expect($target.style.width).to.equal('128px'); $target.setAttribute('data-width', '256px'); tl.refresh().restart().seek(200); expect($target.style.width).to.equal('256px'); }); test('Stretch a timer', () => { const timer1 = createTimer({ duration: 1273, autoplay: false, }); expect(timer1.duration).to.equal(1273); for (let i = 0, l = 9999; i < l; i++) { const newTime = 1 + i; timer1.stretch(newTime); expect(timer1.duration).to.equal(newTime); expect(timer1.iterationDuration).to.equal(newTime); } timer1.stretch(0); expect(timer1.duration).to.equal(minValue); expect(timer1.iterationDuration).to.equal(minValue); }); test('Stretch a looped timer', () => { const timer1 = createTimer({ duration: 1273, autoplay: false, loop: 3, }); expect(timer1.duration).to.equal(1273 * 4); for (let i = 0, l = 9999; i < l; i++) { const newTime = 1 + i; timer1.stretch(newTime); expect(timer1.duration).to.equal(newTime); expect(timer1.iterationDuration).to.equal(newTime / timer1.iterationCount); } timer1.stretch(0); expect(timer1.duration).to.equal(minValue); expect(timer1.iterationDuration).to.equal(minValue); }); test('Stretch an animation', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { width: [{to: 100, duration: 100}, {to: 100, duration: 200}], duration: 100, autoplay: false }); expect(animation1.duration).to.equal(300); expect(getChildAtIndex(animation1, 0)._updateDuration).to.equal(100); expect(getChildAtIndex(animation1, 1)._updateDuration).to.equal(200); animation1.stretch(600); expect(animation1.duration).to.equal(600); expect(getChildAtIndex(animation1, 0)._updateDuration).to.equal(200); expect(getChildAtIndex(animation1, 1)._updateDuration).to.equal(400); animation1.stretch(30); expect(animation1.duration).to.equal(30); expect(getChildAtIndex(animation1, 0)._updateDuration).to.equal(10); expect(getChildAtIndex(animation1, 1)._updateDuration).to.equal(20); animation1.stretch(0); expect(animation1.duration).to.equal(minValue); expect(getChildAtIndex(animation1, 0)._updateDuration).to.equal(minValue); expect(getChildAtIndex(animation1, 1)._updateDuration).to.equal(minValue); // NOTE: Once an animation duration has been stretched to 0, all tweens are set to 0 animation1.stretch(30); expect(animation1.duration).to.equal(30); expect(getChildAtIndex(animation1, 0)._updateDuration).to.equal(30); expect(getChildAtIndex(animation1, 1)._updateDuration).to.equal(30); }); test('Stretch an timeline', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline() .add($target, { width: [{to: 100, duration: 100}, {to: 100, duration: 200}], }) .add($target, { width: [{to: 100, duration: 100}, {to: 100, duration: 200}], }) expect(tl.duration).to.equal(600); expect(getChildAtIndex(tl, 0).duration).to.equal(300); expect(getChildAtIndex(tl, 1).duration).to.equal(300); tl.stretch(1200); expect(tl.duration).to.equal(1200); expect(getChildAtIndex(tl, 0).duration).to.equal(600); expect(getChildAtIndex(tl, 1).duration).to.equal(600); tl.stretch(300); expect(tl.duration).to.equal(300); expect(getChildAtIndex(tl, 0).duration).to.equal(150); expect(getChildAtIndex(tl, 1).duration).to.equal(150); }); test('Stretch scales keyframe delays proportionally', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { width: [ { from: 0, to: 100, duration: 100 }, { to: 500, delay: 200, duration: 500 }, { to: 300, delay: 150, duration: 100 }, ], autoplay: false, }); expect(animation1.duration).to.equal(1050); const tween0 = getChildAtIndex(animation1, 0); const tween1 = getChildAtIndex(animation1, 1); const tween2 = getChildAtIndex(animation1, 2); expect(tween0._delay).to.equal(0); expect(tween0._updateDuration).to.equal(100); expect(tween0._startTime).to.equal(0); expect(tween1._delay).to.equal(200); expect(tween1._updateDuration).to.equal(500); expect(tween1._startTime).to.equal(300); expect(tween2._delay).to.equal(150); expect(tween2._updateDuration).to.equal(100); expect(tween2._startTime).to.equal(950); animation1.stretch(2100); expect(animation1.duration).to.equal(2100); expect(tween0._delay).to.equal(0); expect(tween0._updateDuration).to.equal(200); expect(tween0._startTime).to.equal(0); expect(tween1._delay).to.equal(400); expect(tween1._updateDuration).to.equal(1000); expect(tween1._startTime).to.equal(600); expect(tween2._delay).to.equal(300); expect(tween2._updateDuration).to.equal(200); expect(tween2._startTime).to.equal(1900); animation1.stretch(525); expect(animation1.duration).to.equal(525); expect(tween0._delay).to.equal(0); expect(tween0._updateDuration).to.equal(50); expect(tween1._delay).to.equal(100); expect(tween1._updateDuration).to.equal(250); expect(tween1._startTime).to.equal(150); expect(tween2._delay).to.equal(75); expect(tween2._updateDuration).to.equal(50); expect(tween2._startTime).to.equal(475); }); test('Stretch scales global delay and keyframe delays proportionally', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { width: [ { from: 0, to: 100, duration: 100 }, { to: 200, delay: 200, duration: 300 }, ], delay: 50, autoplay: false, }); expect(animation1.duration).to.equal(600); expect(animation1._delay).to.equal(50); const tween0 = getChildAtIndex(animation1, 0); const tween1 = getChildAtIndex(animation1, 1); expect(tween0._delay).to.equal(0); expect(tween0._updateDuration).to.equal(100); expect(tween1._delay).to.equal(200); expect(tween1._updateDuration).to.equal(300); expect(tween1._startTime).to.equal(300); animation1.stretch(1200); expect(animation1.duration).to.equal(1200); expect(animation1._delay).to.equal(100); expect(tween0._delay).to.equal(0); expect(tween0._updateDuration).to.equal(200); expect(tween1._delay).to.equal(400); expect(tween1._updateDuration).to.equal(600); expect(tween1._startTime).to.equal(600); }); test('Stretch a timeline scales keyframe delays of animation children', () => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline({ autoplay: false }) .add($target, { width: [ { from: 0, to: 100, duration: 100 }, { to: 200, delay: 200, duration: 300 }, ], }) .add($target, { height: [ { from: 0, to: 100, duration: 100 }, { to: 200, delay: 100, duration: 200 }, ], }); const child0 = getChildAtIndex(tl, 0); const child1 = getChildAtIndex(tl, 1); expect(child0.duration).to.equal(600); expect(child1.duration).to.equal(400); expect(tl.duration).to.equal(1000); const c0t0 = getChildAtIndex(child0, 0); const c0t1 = getChildAtIndex(child0, 1); const c1t0 = getChildAtIndex(child1, 0); const c1t1 = getChildAtIndex(child1, 1); expect(c0t1._delay).to.equal(200); expect(c0t1._updateDuration).to.equal(300); expect(c1t1._delay).to.equal(100); expect(c1t1._updateDuration).to.equal(200); tl.stretch(2000); expect(tl.duration).to.equal(2000); expect(child0.duration).to.equal(1200); expect(child1.duration).to.equal(800); expect(c0t0._delay).to.equal(0); expect(c0t0._updateDuration).to.equal(200); expect(c0t1._delay).to.equal(400); expect(c0t1._updateDuration).to.equal(600); expect(c0t1._startTime).to.equal(600); expect(c1t0._delay).to.equal(0); expect(c1t0._updateDuration).to.equal(200); expect(c1t1._delay).to.equal(200); expect(c1t1._updateDuration).to.equal(400); expect(c1t1._startTime).to.equal(400); }); test('Seek an animation', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const animation1 = animate($target, { width: 200, duration: 200, autoplay: false }); expect(animation1.currentTime).to.equal(0); expect(animation1.progress).to.equal(0); expect(animation1.began).to.equal(false); expect(animation1.completed).to.equal(false); animation1.seek(100); expect(animation1.currentTime).to.equal(100); expect(animation1.progress).to.equal(.5); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(false); animation1.seek(200); expect(animation1.currentTime).to.equal(200); expect(animation1.progress).to.equal(1); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(true); animation1.seek(150); expect(animation1.currentTime).to.equal(150); expect(animation1.progress).to.equal(.75); expect(animation1.began).to.equal(true); expect(animation1.completed).to.equal(false); animation1.resume(); createTimer({ duration: 65, onComplete: () => { animation1.pause(); expect(animation1.currentTime).to.equal(200); expect(animation1.progress).to.equal(1); expect(animation1.completed).to.equal(true); resolve(); } }); }); test('Seek a timeline', resolve => { const $target = /** @type {HTMLElement} */(document.querySelector('#target-id')); const tl = createTimeline({ autoplay: false }) .add($target, { width: 200, duration: 100 }) .add($target, { width: 400, duration: 100 }); expect(tl.currentTime).to.equal(0); expect(tl.progress).to.equal(0); expect(tl.began).to.equal(false); expect(tl.completed).to.equal(false); tl.seek(100); expect(tl.currentTime).to.equal(100); expect(tl.progress).to.equal(.5); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(false); tl.seek(200); expect(tl.currentTime).to.equal(200); expect(tl.progress).to.equal(1); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(true); tl.seek(150); expect(tl.currentTime).to.equal(150); expect(tl.progress).to.equal(.75); expect(tl.began).to.equal(true); expect(tl.completed).to.equal(false); tl.resume(); createTimer({ duration: 65, onComplete: () => { tl.pause(); expect(tl.currentTime).to.equal(200); expect(tl.progress).to.equal(1); expect(tl.completed).to.equal(true); resolve(); } }); }); });