diff --git a/src/animation.js b/src/animation.js index cecb633..43177ee 100644 --- a/src/animation.js +++ b/src/animation.js @@ -196,7 +196,7 @@ }; if (WEB_ANIMATIONS_TESTING) { - testing.Player = scope.Animation; + testing.webAnimations1Animation = scope.Animation; } })(webAnimations1, webAnimationsTesting); diff --git a/src/keyframe-effect.js b/src/keyframe-effect.js index 21ac214..006a03d 100644 --- a/src/keyframe-effect.js +++ b/src/keyframe-effect.js @@ -59,7 +59,7 @@ }; if (WEB_ANIMATIONS_TESTING) { - testing.webAnimations1Animation = scope.KeyframeEffect; + testing.webAnimations1KeyframeEffect = scope.KeyframeEffect; } })(webAnimationsShared, webAnimations1, webAnimationsTesting); diff --git a/target-config.js b/target-config.js index 7487780..7f307a2 100644 --- a/target-config.js +++ b/target-config.js @@ -79,28 +79,28 @@ 'src/group-constructors.js']; var webAnimations1Test = [ - 'test/js/animation-node.js', + 'test/js/animation-finish-event.js', + 'test/js/animation.js', 'test/js/apply-preserving-inline-style.js', 'test/js/box-handler.js', 'test/js/color-handler.js', 'test/js/dimension-handler.js', + 'test/js/effect-node.js', 'test/js/effect.js', 'test/js/interpolation.js', 'test/js/matrix-interpolation.js', 'test/js/number-handler.js', - 'test/js/player.js', - 'test/js/player-finish-event.js', 'test/js/property-interpolation.js', 'test/js/tick.js', 'test/js/timing.js', 'test/js/transform-handler.js']; var webAnimationsNextTest = webAnimations1Test.concat( - 'test/js/animation-constructor.js', 'test/js/effect-callback.js', + 'test/js/group-animation-finish-event.js', + 'test/js/group-animation.js', 'test/js/group-constructors.js', - 'test/js/group-player.js', - 'test/js/group-player-finish-event.js', + 'test/js/keyframe-effect-constructor.js', 'test/js/timeline.js'); // This object specifies the source and test files for different Web Animation build targets. diff --git a/test/js/animation-constructor.js b/test/js/animation-constructor.js deleted file mode 100644 index f4bbdcc..0000000 --- a/test/js/animation-constructor.js +++ /dev/null @@ -1,80 +0,0 @@ -suite('animation-constructor', function() { - setup(function() { - document.timeline.getAnimations().forEach(function(player) { - player.cancel(); - }); - }); - - test('Playing an Animation makes a Player', function() { - var animation = new Animation(document.body, [], 1000); - assert.equal(document.body.getAnimations().length, 0); - - var player = document.timeline.play(animation); - tick(200); - assert.equal(document.body.getAnimations().length, 1); - - tick(1600); - assert.equal(document.body.getAnimations().length, 0); - }); - - test('Setting the timing function on an Animation works', function() { - function leftAsNumber(target) { - left = getComputedStyle(target).left; - return Number(left.substring(0, left.length - 2)); - } - - var target1 = document.createElement('div'); - var target2 = document.createElement('div'); - target1.style.position = 'absolute'; - target2.style.position = 'absolute'; - document.body.appendChild(target1); - document.body.appendChild(target2); - - var animation1 = new Animation(target1, [{left: '0px'}, {left: '50px'}], 1000); - var animation2 = new Animation(target2, [{left: '0px'}, {left: '50px'}], {duration: 1000, easing: 'ease-in'}); - - var player1 = document.timeline.play(animation1); - var player2 = document.timeline.play(animation2); - - tick(0); - assert.equal(leftAsNumber(target1), 0); - assert.equal(leftAsNumber(target2), 0); - - tick(250); - assert.closeTo(leftAsNumber(target1), 12.5, 1); - assert.closeTo(leftAsNumber(target2), 4.65, 1); - - tick(500); - assert.closeTo(leftAsNumber(target1), 25, 1); - assert.closeTo(leftAsNumber(target2), 15.25, 1); - }); - - test('Timing is always converted to AnimationTimingInput', function() { - var target = document.createElement('div'); - document.body.appendChild(target); - - var keyframes = [{background: 'blue'}, {background: 'red'}]; - - var animation = new Animation(target, keyframes, 200); - assert.equal(animation.timing.duration, 200); - - animation = new Animation(target, keyframes); - assert.isDefined(animation.timing); - - animation = new Animation(target, keyframes, {duration: 200}); - var group = new AnimationGroup([animation]); - assert.equal(group.timing.duration, 'auto'); - }); - - test('Handle null target on Animation', function() { - var animation = new Animation(null, function(tf) { - // noop - }, 200); - - var player = document.timeline.play(animation); - assert.isNotNull(player); - tick(50); - tick(150); - assert.equal(player.currentTime, 100); - }); -}); diff --git a/test/js/player-finish-event.js b/test/js/animation-finish-event.js similarity index 57% rename from test/js/player-finish-event.js rename to test/js/animation-finish-event.js index 6365d91..987d010 100644 --- a/test/js/player-finish-event.js +++ b/test/js/animation-finish-event.js @@ -1,22 +1,22 @@ -suite('player-finish-event', function() { +suite('animation-finish-event', function() { setup(function() { this.element = document.createElement('div'); document.documentElement.appendChild(this.element); - this.player = this.element.animate([], 1000); + this.animation = this.element.animate([], 1000); }); teardown(function() { if (this.element.parent) this.element.removeChild(this.target); }); - test('fire when player completes', function(done) { + test('fire when animation completes', function(done) { var ready = false; var fired = false; - var player = this.player; - player.onfinish = function(event) { + var animation = this.animation; + animation.onfinish = function(event) { assert(ready, 'must not be called synchronously'); - assert.equal(this, player); - assert.equal(event.target, player); + assert.equal(this, animation); + assert.equal(event.target, animation); assert.equal(event.currentTime, 1000); assert.equal(event.timelineTime, 1100); if (fired) @@ -30,27 +30,27 @@ suite('player-finish-event', function() { ready = true; }); - test('fire when reversed player completes', function(done) { - this.player.onfinish = function(event) { + test('fire when reversed animation completes', function(done) { + this.animation.onfinish = function(event) { assert.equal(event.currentTime, 0); assert.equal(event.timelineTime, 1001); done(); }; tick(0); tick(500); - this.player.reverse(); + this.animation.reverse(); tick(501); tick(1001); }); - test('fire after player is cancelled', function(done) { - this.player.onfinish = function(event) { + test('fire after animation is cancelled', function(done) { + this.animation.onfinish = function(event) { assert.equal(event.currentTime, 0); assert.equal(event.timelineTime, 1, 'event must be fired on next sample'); done(); }; tick(0); - this.player.cancel(); + this.animation.cancel(); tick(1); }); @@ -63,17 +63,17 @@ suite('player-finish-event', function() { }; } var toRemove = createHandler(0); - this.player.addEventListener('finish', createHandler(1)); - this.player.addEventListener('finish', createHandler(2)); - this.player.addEventListener('finish', toRemove); - this.player.addEventListener('finish', createHandler(3)); - this.player.removeEventListener('finish', toRemove); - this.player.onfinish = function() { + this.animation.addEventListener('finish', createHandler(1)); + this.animation.addEventListener('finish', createHandler(2)); + this.animation.addEventListener('finish', toRemove); + this.animation.addEventListener('finish', createHandler(3)); + this.animation.removeEventListener('finish', toRemove); + this.animation.onfinish = function() { assert.equal(count, 3); done(); }; tick(0); - this.player.cancel(); + this.animation.cancel(); tick(1000); }); }); diff --git a/test/js/animation.js b/test/js/animation.js new file mode 100644 index 0000000..0624ee3 --- /dev/null +++ b/test/js/animation.js @@ -0,0 +1,470 @@ +suite('animation', function() { + setup(function() { + webAnimations1.timeline._animations = []; + }); + test('zero duration animation works', function() { + tick(90); + var a = document.body.animate([], 0); + tick(100); + assert.equal(a.startTime, 100); + assert.equal(a.currentTime, 0); + }); + test('playing works as expected', function() { + tick(90); + var a = document.body.animate([], 2000); + tick(100); + assert.equal(a.startTime, 100); + assert.equal(a.currentTime, 0); + tick(300); + assert.equal(a.startTime, 100); + assert.equal(a.currentTime, 200); + }); + test('pause at start of play', function() { + tick(90); + var a = document.body.animate([], 2000); + a.pause(); + tick(100); + assert.equal(a.currentTime, 0); + tick(300); + a.play(); + assert.equal(a.currentTime, 0); + tick(310); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 310); + + var a = document.body.animate([], 2000); + a.startTime = -690; + a.pause(); + assert.equal(a.currentTime, null); + tick(700); + a.play(); + tick(701); + assert.equal(a.currentTime, 1000); + tick(800); + assert.equal(a.currentTime, 1099); + assert.equal(a.startTime, -299); + }); + test('pausing works as expected', function() { + tick(190); + var a = document.body.animate([], 3000); + tick(200); + tick(1500); + assert.equal(a.startTime, 200); + assert.equal(a.currentTime, 1300); + a.pause(); + assert.equal(a.startTime, null); + assert.equal(a.currentTime, null); + tick(2500); + assert.equal(a.startTime, null); + assert.equal(a.currentTime, 1300); + a.play(); + tick(2510); + assert.equal(a.startTime, 1210); + assert.equal(a.currentTime, 1300); + tick(3500); + assert.equal(a.startTime, 1210); + assert.equal(a.currentTime, 2290); + }); + test('reversing works as expected', function() { + tick(290); + var a = document.body.animate([], 1000); + tick(300); + assert.equal(a.startTime, 300); + assert.equal(a.currentTime, 0); + tick(600); + assert.equal(a.startTime, 300); + assert.equal(a.currentTime, 300); + assert.equal(a.playbackRate, 1); + a.reverse(); + tick(600); + assert.equal(a.startTime, 900); + assert.equal(a.currentTime, 300); + assert.equal(a.playbackRate, -1); + tick(700); + assert.equal(a.startTime, 900); + assert.equal(a.currentTime, 200); + }); + test('reversing after pausing', function() { + tick(90); + var a = document.body.animate([], 1000); + tick(100); + tick(600); + a.reverse(); + tick(601); + tick(700); + assert.equal(a.startTime, 1101); + assert.equal(a.currentTime, 401); + }); + test('reversing after finishing works as expected', function() { + tick(90); + var a = document.body.animate([], 1000); + tick(100); + tick(1200); + assert.equal(a.finished, true); + assert.equal(a.startTime, 100); + assert.equal(a.currentTime, 1000); + tick(1500); + assert.equal(a.currentTime, 1000); + assert.equal(isTicking(), false); + a.reverse(); + assert.equal(a._startTime, null); + assert.equal(a.currentTime, 1000); + tick(1600); + assert.equal(a.startTime, 2600); + assert.equal(a.currentTime, 1000); + }); + test('playing after finishing works as expected', function() { + tick(90); + var a = document.body.animate([], 1000); + tick(100); + tick(1200); + assert.equal(a.finished, true); + assert.equal(a.startTime, 100); + assert.equal(a.currentTime, 1000); + tick(1500); + assert.equal(a.currentTime, 1000); + assert.equal(isTicking(), false); + a.play(); + assert.equal(a.startTime, null); + assert.equal(a.currentTime, 0); + tick(1600); + assert.equal(a.startTime, 1600); + assert.equal(a.currentTime, 0); + }); + test('limiting works as expected', function() { + tick(390); + var a = document.body.animate([], 1000); + tick(400); + assert.equal(a.startTime, 400); + assert.equal(a.currentTime, 0); + tick(900); + assert.equal(a.startTime, 400); + assert.equal(a.currentTime, 500); + tick(1400); + assert.equal(a.startTime, 400); + assert.equal(a.currentTime, 1000); + tick(1500); + assert.equal(a.startTime, 400); + assert.equal(a.currentTime, 1000); + a.reverse(); + assert.equal(a.playbackRate, -1); + assert.equal(a.currentTime, 1000); + assert.equal(a._startTime, null); + tick(2000); + assert.equal(a.currentTime, 1000); + assert.equal(a.startTime, 3000); + tick(2200); + assert.equal(a.currentTime, 800); + assert.equal(a.startTime, 3000); + tick(3200); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 3000); + tick(3500); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 3000); + }); + test('play after limit works as expected', function() { + tick(490); + var a = document.body.animate([], 2000); + tick(500); + tick(2600); + assert.equal(a.currentTime, 2000); + assert.equal(a.startTime, 500); + assert.equal(a.finished, true); + assert.equal(a.playbackRate, 1); + setTicking(true); + a.play(); + tick(2700); + assert.equal(a.startTime, 2700); + assert.equal(a.currentTime, 0); + assert.equal(a.finished, false); + assert.equal(a.playbackRate, 1); + }); + test('play after limit works as expected (reversed)', function() { + tick(590); + var a = document.body.animate([], 3000); + tick(600); + tick(700); + a.reverse(); + tick(701); + tick(900); + assert.equal(a.startTime, 801); + assert.equal(a.currentTime, 0); + assert.equal(a.finished, true); + assert.equal(a.playbackRate, -1); + setTicking(true); + a.play(); + tick(1000); + assert.equal(a.startTime, 4000); + assert.equal(a.currentTime, 3000); + assert.equal(a.finished, false); + assert.equal(a.playbackRate, -1); + }); + test('seeking works as expected', function() { + tick(690); + var a = document.body.animate([], 2000); + tick(700); + tick(900); + assert.equal(a.currentTime, 200); + a.currentTime = 600; + assert.equal(a.currentTime, 600); + assert.equal(a.startTime, 300); + a.reverse(); + tick(1000); + assert.equal(a.startTime, 1600); + a.currentTime = 300; + assert.equal(a.currentTime, 300); + assert.equal(a.startTime, 1300); + }); + test('seeking while paused works as expected', function() { + tick(790); + var a = document.body.animate([], 1000); + tick(800); + tick(1000); + a.pause(); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + assert.equal(a.paused, true); + a.currentTime = 500; + assert.equal(a.startTime, null); + assert.equal(a.paused, true); + }); + test('setting start time while paused is ignored', function() { + tick(900); + var a = document.body.animate([], 1234); + a.pause(); + assert.equal(a.startTime, null); + assert.equal(a.currentTime, null); + a.startTime = 2232; + assert.equal(a.startTime, null); + assert.equal(a.currentTime, null); + }); + test('setting playbackRate does preserves the current time', function() { + tick(900); + var a = document.body.animate([], 1000); + tick(1100); + var oldCurrentTime = a.currentTime; + a.playbackRate = 2; + assert.equal(a.playbackRate, 2); + assert.equal(a.currentTime, oldCurrentTime); + }); + test('finishing works as expected', function() { + tick(1000); + var a = document.body.animate([], 2000); + a.finish(); + assert.equal(a.startTime, 0); + assert.equal(a.currentTime, 2000); + a.reverse(); + a.finish(); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 2000); + tick(2000); + }); + test('cancelling clears all effects', function() { + tick(0); + var target = document.createElement('div'); + document.documentElement.appendChild(target); + var animation = target.animate([{marginLeft: '50px'}, {marginLeft: '50px'}], 1000); + tick(10); + tick(110); + assert.equal(getComputedStyle(target).marginLeft, '50px'); + animation.cancel(); + // getComputedStyle forces a tick. + assert.equal(getComputedStyle(target).marginLeft, '0px'); + assert.deepEqual(webAnimations1.timeline._animations, []); + tick(120); + assert.equal(getComputedStyle(target).marginLeft, '0px'); + assert.deepEqual(webAnimations1.timeline._animations, []); + document.documentElement.removeChild(target); + }); + test('startTime is set on first tick if timeline hasn\'t started', function() { + webAnimations1.timeline.currentTime = undefined; + var a = document.body.animate([], 1000); + tick(0); + tick(100); + assert.equal(a.startTime, 0); + }); + test('animations which are finished and not filling get discarded', function() { + tick(90); + var nofill = document.body.animate([], 100); + var fill = document.body.animate([], {duration: 100, fill: 'forwards'}); + assert.deepEqual(webAnimations1.timeline._animations, [nofill._animation || nofill, fill._animation || fill]); + tick(100); + assert.deepEqual(webAnimations1.timeline._animations, [nofill._animation || nofill, fill._animation || fill]); + tick(400); + assert.deepEqual(webAnimations1.timeline._animations, [fill._animation || fill]); + }); + test('discarded animations get re-added on modification', function() { + tick(90); + var animation = document.body.animate([], 100); + tick(100); + tick(400); + assert.deepEqual(webAnimations1.timeline._animations, []); + animation.currentTime = 0; + assert.deepEqual(webAnimations1.timeline._animations, [animation._animation || animation]); + }); + test('animations in the before phase are not discarded', function() { + tick(100); + var animation = document.body.animate([], 100); + animation.currentTime = -50; + tick(110); + assert.deepEqual(webAnimations1.timeline._animations, [animation._animation || animation]); + }); + test('animations that go out of effect should not clear the effect of animations that are in effect', function() { + var target = document.createElement('div'); + document.body.appendChild(target); + tick(0); + var animationBehind = target.animate([{marginLeft: '200px'}, {marginLeft: '200px'}], 200); + var animationInfront = target.animate([{marginLeft: '100px'}, {marginLeft: '100px'}], 100); + tick(50); + assert.equal(getComputedStyle(target).marginLeft, '100px', 't = 50'); + tick(150); + assert.equal(getComputedStyle(target).marginLeft, '200px', 't = 150'); + tick(250); + assert.equal(getComputedStyle(target).marginLeft, '0px', 't = 250'); + document.body.removeChild(target); + }); + test('animation modifications should update CSS effects immediately', function() { + var target = document.createElement('div'); + document.body.appendChild(target); + tick(0); + var animationBehind = target.animate([{width: '1234px'}, {width: '1234px'}], {duration: 1, fill: 'both'}); + var animationInfront = target.animate([{width: '0px'}, {width: '100px'}], 100); + assert.equal(getComputedStyle(target).width, '0px'); + animationInfront.currentTime = 50; + assert.equal(getComputedStyle(target).width, '50px'); + animationInfront.currentTime = 100; + assert.equal(getComputedStyle(target).width, '1234px'); + animationInfront.play(); + assert.equal(getComputedStyle(target).width, '0px'); + animationInfront.startTime = -50; + assert.equal(getComputedStyle(target).width, '50px'); + document.body.removeChild(target); + }); + test('KeyframeEffect that hasn\'t been played has playState \'idle\'', function() { + var effect = new webAnimations1KeyframeEffect(document.body, [], 1000); + var a = new webAnimations1Animation(effect); + assert.equal(a.playState, 'idle'); + }); + test('playState works for a simple effect', function() { + var a = document.body.animate([], 1000); + tick(0); + assert.equal(a.playState, 'running'); + tick(100); + assert.equal(a.playState, 'running'); + a.pause(); + assert.equal(a.playState, 'pending'); + tick(101); + assert.equal(a.playState, 'paused'); + a.play(); + assert.equal(a.playState, 'pending'); + tick(102); + assert.equal(a.playState, 'running'); + tick(1002); + assert.equal(a.playState, 'finished'); + }); + test('Play after cancel', function() { + var a = document.body.animate([], 1000); + assert.equal(a.playState, 'pending'); + tick(0); + a.cancel(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + tick(1); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + a.play(); + assert.equal(a.playState, 'pending'); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, null); + tick(10); + assert.equal(a.playState, 'running'); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 10); + }); + test('Reverse after cancel', function() { + var a = document.body.animate([], 300); + tick(0); + a.cancel(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + tick(1); + a.reverse(); + assert.equal(a.playState, 'pending'); + assert.equal(a.currentTime, 300); + assert.equal(a.startTime, null); + tick(100); + assert.equal(a.playState, 'running'); + assert.equal(a.currentTime, 300); + assert.equal(a.startTime, 400); + tick(300); + assert.equal(a.playState, 'running'); + assert.equal(a.currentTime, 100); + assert.equal(a.startTime, 400); + tick(400); + assert.equal(a.playState, 'finished'); + assert.equal(a.currentTime, 0); + assert.equal(a.startTime, 400); + }); + test('Finish after cancel', function() { + var a = document.body.animate([], 300); + tick(0); + a.cancel(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + tick(1); + a.finish(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + tick(2); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + }); + test('Pause after cancel', function() { + var a = document.body.animate([], 300); + tick(0); + a.cancel(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + tick(1); + a.pause(); + assert.equal(a.playState, 'idle'); + assert.equal(a.currentTime, null); + assert.equal(a.startTime, null); + }); + test('Animations ignore NaN times', function() { + var a = document.body.animate([], 300); + a.startTime = 100; + tick(110); + assert.equal(a.currentTime, 10); + a.startTime = NaN; + assert.equal(a.startTime, 100); + a.currentTime = undefined; + assert.equal(a.currentTime, 10); + }); + test('play() should not set a start time', function() { + var a = document.body.animate([], 1000); + a.cancel(); + assert.equal(a.startTime, null); + assert.equal(a.playState, 'idle'); + a.play(); + assert.equal(a.startTime, null); + assert.equal(a.playState, 'pending'); + }); + test('reverse() should not set a start time', function() { + var a = document.body.animate([], 1000); + a.cancel(); + assert.equal(a.startTime, null); + assert.equal(a.playState, 'idle'); + a.reverse(); + assert.equal(a.startTime, null); + assert.equal(a.playState, 'pending'); + }); +}); diff --git a/test/js/effect-callback.js b/test/js/effect-callback.js index a4e7c69..d441d41 100644 --- a/test/js/effect-callback.js +++ b/test/js/effect-callback.js @@ -7,18 +7,18 @@ suite('effect-callback', function() { test('animations starting in the future are not in effect', function() { var fractions = []; tick(100); - var player = document.body.animate(function(fraction) { fractions.push(fraction); }, 1000); - player.startTime = 1000; + var animation = document.body.animate(function(fraction) { fractions.push(fraction); }, 1000); + animation.startTime = 1000; tick(200); tick(1000); tick(1100); assert.deepEqual(fractions, [0, 0.1]); }); - test('duration 0 players get sampled at least once', function() { + test('duration 0 animations get sampled at least once', function() { var timeFraction; tick(0); - var player = document.body.animate(function(t) { + var animation = document.body.animate(function(t) { timeFraction = t; }, {duration: 0, fill: 'both'}); tick(100); @@ -26,33 +26,33 @@ suite('effect-callback', function() { assert.equal(isTicking(), false); }); - test('players added during custom effect callbacks get updated in the same tick', function() { - var player; + test('animations added during custom effect callbacks get updated in the same tick', function() { + var animation; var called = false; tick(0); document.body.animate(function() { - player = document.body.animate(function() { + animation = document.body.animate(function() { called = true; }, 1); }, 2); tick(1); - assert.isTrue(player.startTime >= 0); + assert.isTrue(animation.startTime >= 0); assert.isFalse(called); }); test('custom effect should be called after cancel', function() { var fractions = []; - var player = document.body.animate(function(fraction) { fractions.push(fraction); }, 1000); + var animation = document.body.animate(function(fraction) { fractions.push(fraction); }, 1000); tick(0); tick(500); - player.cancel(); + animation.cancel(); tick(501); assert.deepEqual(fractions, [0, 0.5, null]); }); - test('element.animate is given animation', function() { + test('element.animate is given effect', function() { var callbackAnim; - var player = document.body.animate(function(t, target, a) { + var animation = document.body.animate(function(t, target, a) { callbackAnim = a; }, 100); tick(50); @@ -62,15 +62,15 @@ suite('effect-callback', function() { assert.equal(callbackAnim.target, document.body); }); - test('effect callback on animation is given source animation', function() { + test('custom callback on effect is given source effect', function() { var callbackAnim; - var anim = new Animation(document.body, function(t, target, a) { + var effect = new KeyframeEffect(document.body, function(t, target, a) { callbackAnim = a; }, 1000); - var player = document.timeline.play(anim); + var animation = document.timeline.play(effect); tick(50); tick(550); - assert.equal(player.currentTime, 500); - assert.equal(callbackAnim, anim); + assert.equal(animation.currentTime, 500); + assert.equal(callbackAnim, effect); }); }); diff --git a/test/js/animation-node.js b/test/js/effect-node.js similarity index 98% rename from test/js/animation-node.js rename to test/js/effect-node.js index 13a864f..f41482e 100644 --- a/test/js/animation-node.js +++ b/test/js/effect-node.js @@ -1,4 +1,4 @@ -suite('animation-node', function() { +suite('effect-node', function() { test('normalize timing input', function() { assert.equal(normalizeTimingInput(1).duration, 1); assert.equal(normalizeTimingInput(1).easing(0.2), 0.2); @@ -90,7 +90,7 @@ suite('animation-node', function() { assert.closeTo(calculateTransformedTime(4, 1000, 600, {easing: function(x) { return x * x; }, direction: 'alternate-reverse'}), 160, 0.0001); assert.closeTo(calculateTransformedTime(3, 1000, 600, {easing: function(x) { return x * x; }, direction: 'alternate-reverse'}), 360, 0.0001); }); - test('Animation Node', function() { + test('Effect Node', function() { var timing = normalizeTimingInput({duration: 1000, iterations: 4, iterationStart: 0.5, easing: 'linear', direction: 'alternate', delay: 100, fill: 'forwards'}); var timing2 = normalizeTimingInput({duration: 1000, iterations: 4, iterationStart: 0.5, easing: 'ease', direction: 'alternate', delay: 100, fill: 'forwards'}); var node = webAnimations1.EffectNode(timing); diff --git a/test/js/effect.js b/test/js/effect.js index 4772663..f2c0b49 100644 --- a/test/js/effect.js +++ b/test/js/effect.js @@ -230,7 +230,7 @@ suite('effect', function() { }); // Test makePropertySpecificKeyframeGroups. - test('Make property specific keyframe groups for a simple effect with one property.', function() { + test('Make property specific keyframe groups for a simple keyframe list with one property.', function() { var groups; assert.doesNotThrow(function() { groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ @@ -249,7 +249,7 @@ suite('effect', function() { assert.equal(groups.left[2].value, '0px'); }); - test('Make property specific keyframe groups for an effect with three properties.', function() { + test('Make property specific keyframe groups for an keyframe list with three properties.', function() { var groups; assert.doesNotThrow(function() { groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ @@ -370,14 +370,14 @@ suite('effect', function() { document.body.appendChild(target1); document.body.appendChild(target2); - var player1 = target1.animate( + var animation1 = target1.animate( [ {left: '0px'}, {left: '50px', offset: 0.25}, {left: '0px'} ], {duration: 4000, fill: 'forwards'}); - var player2 = target2.animate( + var animation2 = target2.animate( [ {left: '0px', easing: 'ease-in'}, {left: '50px', offset: 0.25}, @@ -407,7 +407,7 @@ suite('effect', function() { }); // Test makeInterpolations. - test('Make interpolations for a simple effect with one property.', function() { + test('Make interpolations for a simple keyframe list with one property.', function() { var interpolations; assert.doesNotThrow(function() { interpolations = makeInterpolations(makePropertySpecificKeyframeGroups(normalizeKeyframes([ @@ -441,58 +441,58 @@ suite('effect-convertEffectInput', function() { this.target.removeChild(this.target); }); - test('Convert effect input for a simple effect with one property.', function() { - var effectFunction; + test('Convert effect input for a simple keyframe list with one property.', function() { + var effectInputFunction; assert.doesNotThrow(function() { - effectFunction = webAnimations1.convertEffectInput([ + effectInputFunction = webAnimations1.convertEffectInput([ {left: '0px'}, {left: '200px', offset: 0.3}, {left: '100px'} ]); }); - effectFunction(this.target, 0); + effectInputFunction(this.target, 0); assert.closeTo(leftAsNumber(this.target), 0, 0.001); - effectFunction(this.target, 0.075); + effectInputFunction(this.target, 0.075); assert.closeTo(leftAsNumber(this.target), 50, 0.001); - effectFunction(this.target, 0.15); + effectInputFunction(this.target, 0.15); assert.closeTo(leftAsNumber(this.target), 100, 0.001); - effectFunction(this.target, 0.65); + effectInputFunction(this.target, 0.65); assert.closeTo(leftAsNumber(this.target), 150, 0.001); - effectFunction(this.target, 1); + effectInputFunction(this.target, 1); assert.closeTo(leftAsNumber(this.target), 100, 0.001); - effectFunction(this.target, 2); + effectInputFunction(this.target, 2); assert.closeTo(leftAsNumber(this.target), -42.856, 0.01); }); test('Convert effect input where one property is animated and the property has two keyframes at offset 1.', function() { - var effectFunction; + var effectInputFunction; assert.doesNotThrow(function() { - effectFunction = webAnimations1.convertEffectInput([ + effectInputFunction = webAnimations1.convertEffectInput([ {left: '0px', offset: 0}, {left: '20px', offset: 1}, {left: '30px'} ]); }); - effectFunction(this.target, 1); + effectInputFunction(this.target, 1); assert.equal(getComputedStyle(this.target).left, '30px'); - effectFunction(this.target, 2); + effectInputFunction(this.target, 2); assert.equal(getComputedStyle(this.target).left, '30px'); }); - test('Convert effect input and apply effect at fraction null.', function() { - var effectFunction; + test('Convert effect input and apply result at fraction null.', function() { + var effectInputFunction; var underlying = getComputedStyle(this.target).left; assert.doesNotThrow(function() { - effectFunction = webAnimations1.convertEffectInput([ + effectInputFunction = webAnimations1.convertEffectInput([ {left: '0px'}, {left: '100px'} ]); }); - effectFunction(this.target, 1); + effectInputFunction(this.target, 1); assert.equal(getComputedStyle(this.target).left, '100px'); - effectFunction(this.target, null); + effectInputFunction(this.target, null); assert.equal(getComputedStyle(this.target).left, underlying); }); }); diff --git a/test/js/group-player-finish-event.js b/test/js/group-animation-finish-event.js similarity index 52% rename from test/js/group-player-finish-event.js rename to test/js/group-animation-finish-event.js index 5fedd7e..c3ad7a5 100644 --- a/test/js/group-player-finish-event.js +++ b/test/js/group-animation-finish-event.js @@ -1,30 +1,30 @@ -suite('group-player-finish-event', function() { +suite('group-animation-finish-event', function() { setup(function() { document.timeline.currentTime = undefined; this.element = document.createElement('div'); document.documentElement.appendChild(this.element); - var animation = new AnimationSequence([ - new Animation(this.element, [], 500), - new AnimationGroup([ - new Animation(this.element, [], 250), - new Animation(this.element, [], 500), + var sequenceEffect = new SequenceEffect([ + new KeyframeEffect(this.element, [], 500), + new GroupEffect([ + new KeyframeEffect(this.element, [], 250), + new KeyframeEffect(this.element, [], 500), ]), ]); - this.player = document.timeline.play(animation, 1000); + this.animation = document.timeline.play(sequenceEffect, 1000); }); teardown(function() { if (this.element.parent) this.element.removeChild(this.element); }); - test('fire when player completes', function(done) { + test('fire when animation completes', function(done) { var ready = false; var fired = false; - var player = this.player; - player.onfinish = function(event) { + var animation = this.animation; + animation.onfinish = function(event) { assert(ready, 'must not be called synchronously'); - assert.equal(this, player); - assert.equal(event.target, player); + assert.equal(this, animation); + assert.equal(event.target, animation); assert.equal(event.currentTime, 1000); assert.equal(event.timelineTime, 1100); if (fired) @@ -38,27 +38,27 @@ suite('group-player-finish-event', function() { ready = true; }); - test('fire when reversed player completes', function(done) { - this.player.onfinish = function(event) { + test('fire when reversed animation completes', function(done) { + this.animation.onfinish = function(event) { assert.equal(event.currentTime, 0); assert.equal(event.timelineTime, 1001); done(); }; tick(0); tick(500); - this.player.reverse(); + this.animation.reverse(); tick(501); tick(1001); }); - test('fire after player is cancelled', function(done) { - this.player.onfinish = function(event) { + test('fire after animation is cancelled', function(done) { + this.animation.onfinish = function(event) { assert.equal(event.currentTime, 0); assert.equal(event.timelineTime, 1, 'event must be fired on next sample'); done(); }; tick(0); - this.player.cancel(); + this.animation.cancel(); tick(1); }); @@ -71,17 +71,17 @@ suite('group-player-finish-event', function() { }; } var toRemove = createHandler(0); - this.player.addEventListener('finish', createHandler(1)); - this.player.addEventListener('finish', createHandler(2)); - this.player.addEventListener('finish', toRemove); - this.player.addEventListener('finish', createHandler(3)); - this.player.removeEventListener('finish', toRemove); - this.player.onfinish = function() { + this.animation.addEventListener('finish', createHandler(1)); + this.animation.addEventListener('finish', createHandler(2)); + this.animation.addEventListener('finish', toRemove); + this.animation.addEventListener('finish', createHandler(3)); + this.animation.removeEventListener('finish', toRemove); + this.animation.onfinish = function() { assert.equal(count, 3); done(); }; tick(0); - this.player.cancel(); + this.animation.cancel(); tick(1000); }); }); diff --git a/test/js/group-animation.js b/test/js/group-animation.js new file mode 100644 index 0000000..9e794f5 --- /dev/null +++ b/test/js/group-animation.js @@ -0,0 +1,1043 @@ +suite('group-animation', function() { + setup(function() { + document.timeline._animations = []; + webAnimations1.timeline._animations = []; + this.elements = []; + + var marginEffect = function(target) { + return new KeyframeEffect( + target, + [ + {marginLeft: '0px'}, + {marginLeft: '100px'} + ], + 500); + }; + var colorEffect = function(target) { + return new KeyframeEffect( + target, + [ + {backgroundColor: 'black'}, + {backgroundColor: 'white'} + ], + 500); + }; + var sequenceEmpty = function() { + return new SequenceEffect(); + }; + var groupEmpty = function() { + return new GroupEffect(); + }; + var sequenceWithContent = function(target) { + return new SequenceEffect( + [ + marginEffect(target), + colorEffect(target) + ]); + }; + var groupWithContent = function(target) { + return new GroupEffect( + [ + marginEffect(target), + colorEffect(target) + ]); + }; + + var emptySeq = sequenceEmpty(); + + var seqSimple_target = document.createElement('div'); + this.elements.push(seqSimple_target); + var seqSimple = sequenceWithContent(seqSimple_target); + + var seqWithSeq_target = document.createElement('div'); + this.elements.push(seqWithSeq_target); + var seqWithSeq = new SequenceEffect( + [ + marginEffect(seqWithSeq_target), + colorEffect(seqWithSeq_target), + sequenceWithContent(seqWithSeq_target) + ]); + + var seqWithGroup_target = document.createElement('div'); + this.elements.push(seqWithGroup_target); + var seqWithGroup = new SequenceEffect( + [ + marginEffect(seqWithGroup_target), + colorEffect(seqWithGroup_target), + groupWithContent(seqWithGroup_target) + ]); + + var seqWithEmptyGroup = new SequenceEffect([groupEmpty()]); + var seqWithEmptySeq = new SequenceEffect([sequenceEmpty()]); + + var emptyGroup = groupEmpty(); + + var groupSimple_target = document.createElement('div'); + var groupSimple = groupWithContent(groupSimple_target); + + var groupWithSeq_target = document.createElement('div'); + this.elements.push(groupWithSeq_target); + var groutWithSeq = new GroupEffect( + [ + marginEffect(groupWithSeq_target), + colorEffect(groupWithSeq_target), + sequenceWithContent(groupWithSeq_target) + ]); + + var groupWithGroup_target = document.createElement('div'); + this.elements.push(groupWithGroup_target); + var groupWithGroup = new GroupEffect( + [ + marginEffect(groupWithGroup_target), + colorEffect(groupWithGroup_target), + groupWithContent(groupWithGroup_target) + ]); + + var groupWithEmptyGroup = new GroupEffect([groupEmpty()]); + var groupWithEmptySeq = new GroupEffect([sequenceEmpty()]); + + this.emptySeq = emptySeq; + this.seqSimple = seqSimple; + this.seqWithSeq = seqWithSeq; + this.seqWithGroup = seqWithGroup; + this.seqWithEmptyGroup = seqWithEmptyGroup; + this.seqWithEmptySeq = seqWithEmptySeq; + + this.emptyGroup = emptyGroup; + this.groupSimple = groupSimple; + this.groutWithSeq = groutWithSeq; + this.groupWithGroup = groupWithGroup; + this.groupWithEmptyGroup = groupWithEmptyGroup; + this.groupWithEmptySeq = groupWithEmptySeq; + + this.staticEffect = function(target, value, duration) { + var keyframeEffect = new KeyframeEffect(target, [{marginLeft: value}, {marginLeft: value}], duration); + keyframeEffect.testValue = value; + return keyframeEffect; + }; + // The following animation structure looks like: + // 44444 + // 11 + // 33 + // 2 + // 0 + this.complexTarget = document.createElement('div'); + this.elements.push(this.complexTarget); + this.complexSource = new GroupEffect([ + this.staticEffect(this.complexTarget, '4px', 5), + new SequenceEffect([ + this.staticEffect(this.complexTarget, '1px', 2), + new GroupEffect([ + this.staticEffect(this.complexTarget, '3px', 2), + this.staticEffect(this.complexTarget, '2px', 1), + ]), + ]), + this.staticEffect(this.complexTarget, '0px', 1), + ]); + + this.target = document.createElement('div'); + this.elements.push(this.target); + + for (var i = 0; i < this.elements.length; i++) + document.documentElement.appendChild(this.elements[i]); + }); + + teardown(function() { + for (var i = 0; i < this.elements.length; i++) { + if (this.elements[i].parent) + this.elements[i].parent.removeChild(this.elements[i]); + } + }); + + function simpleGroupEffect() { + return new GroupEffect([new KeyframeEffect(document.body, [], 2000), new KeyframeEffect(document.body, [], 1000), new KeyframeEffect(document.body, [], 3000)]); + } + + function simpleSequenceEffect() { + return new SequenceEffect([new KeyframeEffect(document.body, [], 2000), new KeyframeEffect(document.body, [], 1000), new KeyframeEffect(document.body, [], 3000)]); + } + + // FIXME: Remove _startOffset. + // animationState is [startTime, currentTime, _startOffset?, offset?] + // innerAnimationStates is a nested array tree of animationStates e.g. [[0, 0], [[1, -1], [2, -2]]] + function checkTimes(animation, animationState, innerAnimationStates, description) { + description = description ? (description + ' ') : ''; + _checkTimes(animation, animationState, 0, description + 'top animation'); + _checkTimes(animation, innerAnimationStates, 0, description + 'inner animation'); + } + + function _checkTimes(animation, timingList, index, trace) { + assert.isDefined(animation, trace + ' exists'); + if (timingList.length == 0) { + assert.equal(animation._childAnimations.length, index, trace + ' no remaining animations'); + return; + } + if (timingList[0] === null || typeof timingList[0] == 'number') { + assert.equal(animation.startTime, timingList[0], trace + ' startTime'); + assert.equal(animation.currentTime, timingList[1], trace + ' currentTime'); + } else { + _checkTimes(animation._childAnimations[index], timingList[0], 0, trace + ' ' + index); + _checkTimes(animation, timingList.slice(1), index + 1, trace); + } + } + + test('playing a GroupEffect works as expected', function() { + tick(90); + var a = document.timeline.play(simpleGroupEffect()); + checkTimes(a, [null, 0], [[null, 0], [null, 0], [null, 0]]); + tick(100); + checkTimes(a, [100, 0], [[100, 0], [100, 0], [100, 0]]); + tick(300); + checkTimes(a, [100, 200], [[100, 200], [100, 200], [100, 200]]); + tick(1200); + checkTimes(a, [100, 1100], [[100, 1100], [100, 1000], [100, 1100]]); + tick(2200); + checkTimes(a, [100, 2100], [[100, 2000], [100, 1000], [100, 2100]]); + tick(3200); + checkTimes(a, [100, 3000], [[100, 2000], [100, 1000], [100, 3000]]); + }); + + test('can seek a GroupEffect', function() { + tick(90); + var a = document.timeline.play(simpleGroupEffect()); + tick(100); + checkTimes(a, [100, 0], [[100, 0], [100, 0], [100, 0]]); + a.currentTime = 200; + checkTimes(a, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]); + a.currentTime = 1100; + checkTimes(a, [-1000, 1100], [[-1000, 1100], [-1000, 1100], [-1000, 1100]]); + a.currentTime = 2100; + checkTimes(a, [-2000, 2100], [[-2000, 2100], [-2000, 2100], [-2000, 2100]]); + a.currentTime = 3100; + checkTimes(a, [-3000, 3100], [[-3000, 3100], [-3000, 3100], [-3000, 3100]]); + }); + + test('can startTime seek a GroupEffect', function() { + tick(90); + var a = document.timeline.play(simpleGroupEffect()); + tick(100); + checkTimes(a, [100, 0], [[100, 0], [100, 0], [100, 0]]); + a.startTime = -100; + checkTimes(a, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]); + a.startTime = -1000; + checkTimes(a, [-1000, 1100], [[-1000, 1100], [-1000, 1000], [-1000, 1100]]); + a.startTime = -2000; + checkTimes(a, [-2000, 2100], [[-2000, 2000], [-2000, 1000], [-2000, 2100]]); + a.startTime = -3000; + checkTimes(a, [-3000, 3000], [[-3000, 2000], [-3000, 1000], [-3000, 3000]]); + }); + + test('playing a SequenceEffect works as expected', function() { + tick(100); + var a = document.timeline.play(simpleSequenceEffect()); + tick(110); + checkTimes(a, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); + tick(210); + checkTimes(a, [110, 100], [[110, 100], [2110, -1900], [3110, -2900]]); + tick(2210); + checkTimes(a, [110, 2100], [[110, 2000], [2110, 100], [3110, -900]]); + tick(3210); + checkTimes(a, [110, 3100], [[110, 2000], [2110, 1000], [3110, 100]]); + tick(6210); + checkTimes(a, [110, 6000], [[110, 2000], [2110, 1000], [3110, 3000]]); + }); + + test('can seek a SequenceEffect', function() { + tick(100); + var a = document.timeline.play(simpleSequenceEffect()); + tick(110); + checkTimes(a, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); + a.currentTime = 100; + checkTimes(a, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]); + a.currentTime = 2100; + checkTimes(a, [-1990, 2100], [[-1990, 2100], [10, 100], [1010, -900]]); + a.currentTime = 3100; + checkTimes(a, [-2990, 3100], [[-2990, 3100], [-990, 1100], [10, 100]]); + a.currentTime = 6100; + checkTimes(a, [-5990, 6100], [[-5990, 6100], [-3990, 4100], [-2990, 3100]]); + }); + + test('can startTime seek a SequenceEffect', function() { + tick(100); + var a = document.timeline.play(simpleSequenceEffect()); + tick(110); + checkTimes(a, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); + a.startTime = 10; + checkTimes(a, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]); + a.startTime = -1990; + checkTimes(a, [-1990, 2100], [[-1990, 2000], [10, 100], [1010, -900]]); + a.startTime = -2990; + checkTimes(a, [-2990, 3100], [[-2990, 2000], [-990, 1000], [10, 100]]); + a.startTime = -5990; + checkTimes(a, [-5990, 6000], [[-5990, 2000], [-3990, 1000], [-2990, 3000]]); + }); + + test('complex animation tree timing while playing', function() { + tick(90); + var animation = document.timeline.play(this.complexSource); + tick(100); + checkTimes(animation, [100, 0], [ + [100, 0], [ // 4 + [100, 0], [ // 1 + [102, -2], // 3 + [102, -2]]], // 2 + [100, 0], // 0 + ], 't = 100'); + tick(101); + checkTimes(animation, [100, 1], [ + [100, 1], [ // 4 + [100, 1], [ // 1 + [102, -1], // 3 + [102, -1]]], // 2 + [100, 1], // 0 + ], 't = 101'); + tick(102); + checkTimes(animation, [100, 2], [ + [100, 2], [ // 4 + [100, 2], [ // 1 + [102, 0], // 3 + [102, 0]]], // 2 + [100, 1], // 0 + ], 't = 102'); + }); + + test('effects apply in the correct order', function() { + tick(0); + var animation = document.timeline.play(this.complexSource); + animation.currentTime = 0; + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); + animation.currentTime = 1; + checkTimes(animation, [-1, 1], [[-1, 1, 0], [[-1, 1, 0], [[1, -1, 0], [1, -1, 0]]], [-1, 1, 0]]); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '1px'); + animation.currentTime = 2; + // TODO: When we seek we don't limit. Is this OK? + checkTimes(animation, [-2, 2], [[-2, 2, 0], [[-2, 2, 0], [[0, 0, 0], [0, 0, 0]]], [-2, 2, 0]]); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '2px'); + animation.currentTime = 3; + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px'); + animation.currentTime = 4; + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '4px'); + animation.currentTime = 5; + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); + }); + + test('cancelling group animations', function() { + tick(0); + var animation = document.timeline.play(this.complexSource); + tick(1); + tick(4); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px'); + animation.cancel(); + assert.equal(animation.currentTime, null); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); + }); + + test('cancelling group animations before tick', function() { + tick(0); + var animation = document.timeline.play(this.complexSource); + animation.cancel(); + assert.equal(animation.currentTime, null); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); + tick(4); + assert.equal(animation.currentTime, null); + assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); + }); + + test('redundant effect node wrapping', function() { + tick(100); + var keyframeEffect = new SequenceEffect([ + this.staticEffect(this.target, '0px', 1), + new GroupEffect([ + new SequenceEffect([ + this.staticEffect(this.target, '1px', 1), + this.staticEffect(this.target, '2px', 1), + ]), + ]), + ]); + var animation = document.timeline.play(keyframeEffect); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + checkTimes(animation, [100, 0], [ + [100, 0, 0, 0], [[ // 0 + [101, -1, 0, 1], // 1 + [102, -2, 1, 2]]] // 2 + ], 't = 100'); + tick(101); + assert.equal(getComputedStyle(this.target).marginLeft, '1px'); + checkTimes(animation, [100, 1], [ + [100, 1, 0, 0], [[ // 0 + [101, 0, 0, 1], // 1 + [102, -1, 1, 2]]] // 2 + ], 't = 101'); + tick(102); + assert.equal(getComputedStyle(this.target).marginLeft, '2px'); + assert.equal(document.timeline.currentTime, 102); + checkTimes(animation, [100, 2], [ // FIXME: Implement limiting on group animations + [100, 1, 0, 0], [[ // 0 + [101, 1, 0, 1], // 1 + [102, 0, 1, 2]]] // 2 + ], 't = 102'); + tick(103); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + checkTimes(animation, [100, 3], [ // FIXME: Implement limiting on group animations + [100, 1, 0, 0], [[ // 0 + [101, 1, 0, 1], // 1 + [102, 1, 1, 2]]] // 2 + ], 't = 103'); + if (this.target.parent) + this.target.parent.removeChild(target); + }); + + test('setting the playbackRate on group animations', function() { + var group = new GroupEffect([ + new KeyframeEffect(null, [], 1234), + new KeyframeEffect(null, [], 1234), + ]); + var a = document.timeline.play(group); + a.playbackRate = 2; + assert.equal(a._animation.playbackRate, 2, 'Updates the playbackRate of the inner animation'); + a._childAnimations.forEach(function(childAnimation) { + assert.equal(childAnimation.playbackRate, 2, 'It also updates the child animations'); + }); + }); + + test('delays on groups work correctly', function() { + // 444 + // 1 + // 0 + // 33 + // 2 + var keyframeEffect = new GroupEffect([ + new GroupEffect([ + this.staticEffect(this.target, '4px', {duration: 3, delay: 1}), + this.staticEffect(this.target, '1px', {duration: 1, delay: 0}), + ], {delay: 1}), + new SequenceEffect([ + this.staticEffect(this.target, '0px', {duration: 1, delay: 0}), + this.staticEffect(this.target, '3px', {duration: 2, delay: 1}), + this.staticEffect(this.target, '2px', {duration: 1, delay: -2}), + ]), + ]); + var animation = document.timeline.play(keyframeEffect); + tick(100); + checkTimes(animation, [100, 0], [ + [ + [101, -1], + [101, -1], + ], [ + [100, 0], + [101, -1], + [104, -4], + ] + ]); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + tick(101); + assert.equal(getComputedStyle(this.target).marginLeft, '1px'); + tick(102); + assert.equal(getComputedStyle(this.target).marginLeft, '2px'); + tick(103); + assert.equal(getComputedStyle(this.target).marginLeft, '3px'); + tick(104); + assert.equal(getComputedStyle(this.target).marginLeft, '4px'); + tick(105); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + }); + + test('end delays on groups work correctly', function() { + // 11 + // 4 + // 0 + // 33 + // 2 + var keyframeEffect = new SequenceEffect([ + new SequenceEffect([ + this.staticEffect(this.target, '1px', {duration: 2, endDelay: 2}), + this.staticEffect(this.target, '4px', {duration: 1, endDelay: 1}), + ], {endDelay: -6}), + new SequenceEffect([ + this.staticEffect(this.target, '0px', {duration: 1, endDelay: 1}), + this.staticEffect(this.target, '3px', {duration: 2, endDelay: -2}), + this.staticEffect(this.target, '2px', {duration: 1, endDelay: 2}), + ]), + ]); + var animation = document.timeline.play(keyframeEffect); + tick(100); + checkTimes(animation, [100, 0], [ + [ + [100, 0], + [104, -4], + ], [ + [100, 0], + [102, -2], + [102, -2], + ] + ]); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + tick(101); + assert.equal(getComputedStyle(this.target).marginLeft, '1px'); + tick(102); + assert.equal(getComputedStyle(this.target).marginLeft, '2px'); + tick(103); + assert.equal(getComputedStyle(this.target).marginLeft, '3px'); + tick(104); + // FIXME: Group child animation limiting bounds should match the parent animation's limiting bounds. + // assert.equal(getComputedStyle(this.target).marginLeft, '4px'); + // tick(105); + // assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + }); + + test('basic animation operations are working', function() { + var animations = []; + animations.push(document.timeline.play(this.emptySeq)); + animations.push(document.timeline.play(this.seqSimple)); + animations.push(document.timeline.play(this.seqWithSeq)); + animations.push(document.timeline.play(this.seqWithGroup)); + animations.push(document.timeline.play(this.seqWithEmptyGroup)); + animations.push(document.timeline.play(this.seqWithEmptySeq)); + + animations.push(document.timeline.play(this.emptyGroup)); + animations.push(document.timeline.play(this.groupSimple)); + animations.push(document.timeline.play(this.groutWithSeq)); + animations.push(document.timeline.play(this.groupWithGroup)); + animations.push(document.timeline.play(this.groupWithEmptyGroup)); + animations.push(document.timeline.play(this.groupWithEmptySeq)); + + var length = animations.length; + + tick(50); + for (var i = 0; i < length; i++) + animations[i].pause(); + + tick(100); + for (var i = 0; i < length; i++) + animations[i].play(); + + tick(200); + for (var i = 0; i < length; i++) + animations[i].currentTime += 1; + + tick(300); + for (var i = 0; i < length; i++) + animations[i].startTime += 1; + + tick(350); + for (var i = 0; i < length; i++) + animations[i].reverse(); + + tick(400); + for (var i = 0; i < length; i++) + animations[i].finish(); + + tick(500); + tick(600); + for (var i = 0; i < length; i++) + animations[i].cancel(); + + for (var i = 0; i < length; i++) + animations[i].play(); + }); + + test('pausing works as expected with an empty SequenceEffect', function() { + var animation = document.timeline.play(this.emptySeq); + tick(0); + assert.equal(animation.startTime, 0); + assert.equal(animation.currentTime, 0); + + animation.pause(); + assert.equal(animation.startTime, null); + assert.equal(animation.currentTime, 0); + }); + + test('pausing works as expected with a simple SequenceEffect', function() { + var animation = document.timeline.play(this.seqSimple); + var target = this.seqSimple.children[0].target; + tick(0); + checkTimes(animation, [0, 0], [[0, 0], [500, -500]], 't = 0'); + + tick(200); + checkTimes(animation, [0, 200], [[0, 200], [500, -300]], 't = 200'); + + animation.pause(); + checkTimes(animation, [null, null], [[null, null], [null, null]], 't = 200'); + assert.equal(getComputedStyle(target).marginLeft, '40px'); + + tick(300); + checkTimes(animation, [null, 200], [[null, 200], [null, -300]], 't = 300'); + assert.equal(getComputedStyle(target).marginLeft, '40px'); + + animation.play(); + checkTimes(animation, [null, 200], [[null, 200], [null, -300]], 't = 300'); + assert.equal(getComputedStyle(target).marginLeft, '40px'); + + tick(301); + checkTimes(animation, [101, 200], [[101, 200], [601, -300]], 't = 301'); + assert.equal(getComputedStyle(target).marginLeft, '40px'); + + tick(401); + checkTimes(animation, [101, 300], [[101, 300], [601, -200]], 't = 401'); + assert.equal(getComputedStyle(target).marginLeft, '60px'); + + tick(700); + checkTimes(animation, [101, 599], [[101, 500], [601, 99]], 't = 700'); + assert.equal(getComputedStyle(target).marginLeft, '0px'); + }); + + test('pausing before tick works as expected with a simple SequenceEffect', function() { + var animation = document.timeline.play(this.seqSimple); + var target = this.seqSimple.children[0].target; + checkTimes(animation, [null, 0], [[null, 0], [null, -500]], 't = 0'); + + animation.pause(); + checkTimes(animation, [null, null], [[null, null], [null, null]], 't = 0'); + assert.equal(getComputedStyle(target).marginLeft, '0px'); + + tick(10); + checkTimes(animation, [null, 0], [[null, 0], [null, -500]], 't = 10'); + assert.equal(getComputedStyle(target).marginLeft, '0px'); + + tick(20); + checkTimes(animation, [null, 0], [[null, 0], [null, -500]], 't = 10'); + assert.equal(getComputedStyle(target).marginLeft, '0px'); + }); + + test('pausing and seeking before tick works as expected with a simple SequenceEffect', function() { + var animation = document.timeline.play(this.seqSimple); + animation.pause(); + + animation.currentTime = 0; + checkTimes(animation, [null, 0], [[null, 0], [null, -500]], 't = 10'); + + animation.currentTime = 250; + checkTimes(animation, [null, 250], [[null, 250], [null, -250]], 't = 10'); + + animation.currentTime = 500; + checkTimes(animation, [null, 500], [[null, 500], [null, 0]], 't = 10'); + + // FIXME: Expectation should be [null, 1000], [[null, 500], [null, 500]]. + animation.currentTime = 1000; + checkTimes(animation, [null, 1000], [[null, 1000], [null, 500]], 't = 10'); + }); + + test('pausing works as expected with an SequenceEffect inside an SequenceEffect', function() { + var animation = document.timeline.play(this.seqWithSeq); + tick(0); + checkTimes( + animation, + [0, 0], [ + [0, 0], + [500, -500], [ + [1000, -1000], + [1500, -1500]]], + 't = 0'); + + tick(200); + checkTimes( + animation, + [0, 200], [ + [0, 200], + [500, -300], [ + [1000, -800], + [1500, -1300]]], + 't = 200'); + + animation.pause(); + checkTimes( + animation, + [null, null], [ + [null, null], + [null, null], [ + [null, null], + [null, null]]], + 't = 200'); + + tick(300); + checkTimes( + animation, + [null, 200], [ + [null, 200], + [null, -300], [ + [null, -800], + [null, -1300]]], + 't = 300'); + + animation.play(); + tick(310); + checkTimes( + animation, + [110, 200], [ + [110, 200], + [610, -300], [ + [1110, -800], + [1610, -1300]]], + 't = 310'); + + tick(1300); + checkTimes( + animation, + [110, 1190], [ + [110, 500], + [610, 500], [ + [1110, 190], + [1610, -310]]], + 't = 1300'); + + animation.pause(); + checkTimes( + animation, + [null, null], [ + [null, 500], + [null, 500], [ + [null, null], + [null, null]]], + 't = 1300'); + + tick(1400); + checkTimes( + animation, + [null, 1190], [ + [null, 500], + [null, 500], [ + [null, 190], + [null, -310]]], + 't = 1400'); + + animation.play(); + checkTimes( + animation, + [null, 1190], [ + [null, 500], + [null, 500], [ + [null, 190], + [null, -310]]], + 't = 1400'); + + tick(1410); + checkTimes( + animation, + [220, 1190], [ + [220, 500], + [720, 500], [ + [1220, 190], + [1720, -310]]], + 't = 1410'); + + tick(1600); + checkTimes( + animation, + [220, 1380], [ + [220, 500], + [720, 500], [ + [1220, 380], + [1720, -120]]], + 't = 1600'); + + animation.pause(); + checkTimes( + animation, + [null, null], [ + [null, 500], + [null, 500], [ + [null, null], + [null, null]]], + 't = 1600'); + + tick(1700); + checkTimes( + animation, + [null, 1380], [ + [null, 500], + [null, 500], [ + [null, 380], + [null, -120]]], + 't = 1700'); + + animation.play(); + tick(1710); + checkTimes( + animation, + [330, 1380], [ + [330, 500], + [830, 500], [ + [1330, 380], + [1830, -120]]], + 't = 1710'); + + tick(2400); + checkTimes( + animation, + [330, 2000], [ + [330, 500], + [830, 500], [ + [1330, 500], + [1830, 500]]], + 't = 2400'); + }); + + test('pausing works as expected with a GroupEffect inside an SequenceEffect', function() { + var animation = document.timeline.play(this.seqWithGroup); + tick(0); + checkTimes( + animation, + [0, 0], [ + [0, 0], + [500, -500], [ + [1000, -1000], + [1000, -1000]]], + 't = 0'); + + tick(200); + checkTimes( + animation, + [0, 200], [ + [0, 200], + [500, -300], [ + [1000, -800], + [1000, -800]]], + 't = 200'); + + animation.pause(); + checkTimes( + animation, + [null, null], [ + [null, null], + [null, null], [ + [null, null], + [null, null]]], + 't = 200'); + + tick(300); + checkTimes( + animation, + [null, 200], [ + [null, 200], + [null, -300], [ + [null, -800], + [null, -800]]], + 't = 300'); + + animation.play(); + tick(310); + checkTimes( + animation, + [110, 200], [ + [110, 200], + [610, -300], [ + [1110, -800], + [1110, -800]]], + 't = 310'); + + tick(1310); + checkTimes( + animation, + [110, 1200], [ + [110, 500], + [610, 500], [ + [1110, 200], + [1110, 200]]], + 't = 1310'); + + animation.pause(); + checkTimes( + animation, + [null, null], [ + [null, 500], + [null, 500], [ + [null, null], + [null, null]]], + 't = 1310'); + + tick(1400); + checkTimes( + animation, + [null, 1200], [ + [null, 500], + [null, 500], [ + [null, 200], + [null, 200]]], + 't = 1410'); + + animation.play(); + tick(1410); + checkTimes( + animation, + [210, 1200], [ + [210, 500], + [710, 500], [ + [1210, 200], + [1210, 200]]], + 't = 1410'); + + tick(1610); + checkTimes( + animation, + [210, 1400], [ + [210, 500], + [710, 500], [ + [1210, 400], + [1210, 400]]], + 't = 1610'); + + animation.pause(); + tick(1810); + checkTimes( + animation, + [null, 1400], [ + [null, 500], + [null, 500], [ + [null, 400], + [null, 400]]], + 't = 1810'); + + animation.play(); + tick(1820); + checkTimes( + animation, + [420, 1400], [ + [420, 500], + [920, 500], [ + [1420, 400], + [1420, 400]]], + 't = 1820'); + + tick(2020); + checkTimes( + animation, + [420, 1500], [ + [420, 500], + [920, 500], [ + [1420, 500], + [1420, 500]]], + 't = 2020'); + + animation.pause(); + checkTimes( + animation, + [null, 1500], [ + [null, 500], + [null, 500], [ + [null, 500], + [null, 500]]], + 't = 2020'); + }); + + test('pausing works as expected with an empty SequenceEffect inside an SequenceEffect', function() { + var animation = document.timeline.play(this.seqWithEmptySeq); + tick(0); + checkTimes( + animation, + [0, 0], [0, 0], + 't = 0'); + + animation.pause(); + checkTimes( + animation, + [null, 0], [null, 0], + 't = 0 after pause'); + }); + + test('pausing works as expected with an empty GroupEffect inside an SequenceEffect', function() { + var animation = document.timeline.play(this.seqWithEmptyGroup); + tick(0); + checkTimes( + animation, + [0, 0], [0, 0], + 't = 0'); + + animation.pause(); + checkTimes( + animation, + [null, 0], [null, 0], + 't = 0 after pause'); + }); + + test('playState works for groups', function() { + var target = document.createElement('div'); + document.body.appendChild(target); + var keyframeEffect = new SequenceEffect([new KeyframeEffect(target, [], 100), new KeyframeEffect(target, [], 100)]); + var a = document.timeline.play(keyframeEffect); + assert.equal(a.playState, 'pending'); + tick(1); + assert.equal(a.playState, 'running'); + assert.equal(a._childAnimations[0]._animation.playState, 'running'); + assert.equal(a._childAnimations[1]._animation.playState, 'running'); + tick(101); + assert.equal(a.playState, 'running'); + assert.equal(a._childAnimations[0]._animation.playState, 'finished'); + assert.equal(a._childAnimations[1]._animation.playState, 'running'); + a.pause(); + assert.equal(a.playState, 'pending'); + assert.equal(a._childAnimations[0]._animation.playState, 'paused'); + assert.equal(a._childAnimations[1]._animation.playState, 'pending'); + tick(102); + assert.equal(a.playState, 'paused'); + assert.equal(a._childAnimations[0]._animation.playState, 'paused'); + assert.equal(a._childAnimations[1]._animation.playState, 'paused'); + a.play(); + assert.equal(a.playState, 'pending'); + assert.equal(a._childAnimations[0]._animation.playState, 'pending'); + assert.equal(a._childAnimations[1]._animation.playState, 'pending'); + tick(103); + assert.equal(a.playState, 'running'); + assert.equal(a._childAnimations[0]._animation.playState, 'finished'); + assert.equal(a._childAnimations[1]._animation.playState, 'running'); + tick(204); + assert.equal(a.playState, 'finished'); + assert.equal(a._childAnimations[0]._animation.playState, 'finished'); + assert.equal(a._childAnimations[1]._animation.playState, 'finished'); + }); + + test('pausing then seeking out of range then seeking into range works', function() { + var target = document.createElement('div'); + var keyframeEffect = new KeyframeEffect(target, [], {duration: 2000, fill: 'both'}); + var group = new GroupEffect([keyframeEffect], {fill: 'none'}); + var animation = document.timeline.play(group); + + animation.pause(); + animation.currentTime = 3000; + assert.equal(animation._childAnimations.length, 0); + tick(100); + animation.currentTime = 1000; + assert.equal(animation._childAnimations.length, 1); + assert.equal(animation._childAnimations[0]._animation.playState, 'paused'); + assert.equal(animation._childAnimations[0]._animation.currentTime, 1000); + + }); + + test('reversing then seeking out of range then seeking into range works', function() { + var target = document.createElement('div'); + var keyframeEffect = new KeyframeEffect(target, [], {duration: 2000, fill: 'both'}); + var group = new GroupEffect([keyframeEffect], {fill: 'none'}); + var animation = document.timeline.play(group); + + animation.currentTime = 1000; + tick(100); + animation.reverse(); + tick(105); + animation.currentTime = 3000; + assert.equal(animation._childAnimations.length, 0); + tick(110); + animation.currentTime = 1000; + assert.equal(animation.playbackRate, -1); + assert.equal(animation._childAnimations.length, 1); + assert.equal(animation._childAnimations[0]._animation.playState, 'running'); + assert.equal(animation._childAnimations[0]._animation.currentTime, 1000); + assert.equal(animation._childAnimations[0]._animation.playbackRate, -1); + + }); + + test('fill none groups with fill none children do not fill', function() { + var keyframeEffect = new KeyframeEffect( + this.target, + [{marginLeft: '0px'}, {marginLeft: '100px'}], + {duration: 500, fill: 'none'}); + var group = new GroupEffect([keyframeEffect], {fill: 'none'}); + var animation = document.timeline.play(group); + + tick(0); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + tick(250); + assert.equal(getComputedStyle(this.target).marginLeft, '50px'); + tick(501); + assert.equal(getComputedStyle(this.target).marginLeft, '0px'); + tick(502); + }); +}); diff --git a/test/js/group-constructors.js b/test/js/group-constructors.js index e6b272f..b8ba6a6 100644 --- a/test/js/group-constructors.js +++ b/test/js/group-constructors.js @@ -1,26 +1,22 @@ suite('group-constructors', function() { - setup(function() { - document.timeline._players = []; - }); - - function simpleAnimationGroup() { - return new AnimationSequence([ - new Animation(document.body, [], 2000), - new AnimationGroup([ - new Animation(document.body, [], 2000), - new Animation(document.body, [], 1000) + function simpleGroupEffect() { + return new SequenceEffect([ + new KeyframeEffect(document.body, [], 2000), + new GroupEffect([ + new KeyframeEffect(document.body, [], 2000), + new KeyframeEffect(document.body, [], 1000) ]) ]); } - test('player getter for children in groups, and __internalPlayer, work as expected', function() { - var p = document.timeline.play(simpleAnimationGroup()); + test('animation getter for children in groups works as expected', function() { + var anim = document.timeline.play(simpleGroupEffect()); tick(0); - assert.equal(p.effect.animation, p); - assert.equal(p._childAnimations[0].effect.animation, p); - assert.equal(p._childAnimations[1].effect.animation, p); + assert.equal(anim.effect.animation, anim); + assert.equal(anim._childAnimations[0].effect.animation, anim); + assert.equal(anim._childAnimations[1].effect.animation, anim); tick(2100); - assert.equal(p._childAnimations[1]._childAnimations[0].effect.animation, p); - assert.equal(p._childAnimations[1]._childAnimations[1].effect.animation, p); + assert.equal(anim._childAnimations[1]._childAnimations[0].effect.animation, anim); + assert.equal(anim._childAnimations[1]._childAnimations[1].effect.animation, anim); }); }); diff --git a/test/js/group-player.js b/test/js/group-player.js deleted file mode 100644 index eadbe6b..0000000 --- a/test/js/group-player.js +++ /dev/null @@ -1,1044 +0,0 @@ -suite('group-player', function() { - setup(function() { - document.timeline._animations = []; - webAnimations1.timeline._animations = []; - this.elements = []; - - var animationMargin = function(target) { - return new Animation( - target, - [ - {marginLeft: '0px'}, - {marginLeft: '100px'} - ], - 500); - }; - var animationColor = function(target) { - return new Animation( - target, - [ - {backgroundColor: 'black'}, - {backgroundColor: 'white'} - ], - 500); - }; - var sequenceEmpty = function() { - return new AnimationSequence(); - }; - var groupEmpty = function() { - return new AnimationGroup(); - }; - var sequenceWithEffects = function(target) { - return new AnimationSequence( - [ - animationMargin(target), - animationColor(target) - ]); - }; - var groupWithEffects = function(target) { - return new AnimationGroup( - [ - animationMargin(target), - animationColor(target) - ]); - }; - - var seqEmpty_source = sequenceEmpty(); - - var seqSimple_target = document.createElement('div'); - this.elements.push(seqSimple_target); - var seqSimple_source = sequenceWithEffects(seqSimple_target); - - var seqWithSeq_target = document.createElement('div'); - this.elements.push(seqWithSeq_target); - var seqWithSeq_source = new AnimationSequence( - [ - animationMargin(seqWithSeq_target), - animationColor(seqWithSeq_target), - sequenceWithEffects(seqWithSeq_target) - ]); - - var seqWithGroup_target = document.createElement('div'); - this.elements.push(seqWithGroup_target); - var seqWithGroup_source = new AnimationSequence( - [ - animationMargin(seqWithGroup_target), - animationColor(seqWithGroup_target), - groupWithEffects(seqWithGroup_target) - ]); - - var seqWithEmptyGroup_source = new AnimationSequence([groupEmpty()]); - var seqWithEmptySeq_source = new AnimationSequence([sequenceEmpty()]); - - var groupEmpty_source = groupEmpty(); - - var groupSimple_target = document.createElement('div'); - var groupSimple_source = groupWithEffects(groupSimple_target); - - var groupWithSeq_target = document.createElement('div'); - this.elements.push(groupWithSeq_target); - var groupWithSeq_source = new AnimationGroup( - [ - animationMargin(groupWithSeq_target), - animationColor(groupWithSeq_target), - sequenceWithEffects(groupWithSeq_target) - ]); - - var groupWithGroup_target = document.createElement('div'); - this.elements.push(groupWithGroup_target); - var groupWithGroup_source = new AnimationGroup( - [ - animationMargin(groupWithGroup_target), - animationColor(groupWithGroup_target), - groupWithEffects(groupWithGroup_target) - ]); - - var groupWithEmptyGroup_source = new AnimationGroup([groupEmpty()]); - var groupWithEmptySeq_source = new AnimationGroup([sequenceEmpty()]); - - this.seqEmpty_source = seqEmpty_source; - this.seqSimple_source = seqSimple_source; - this.seqWithSeq_source = seqWithSeq_source; - this.seqWithGroup_source = seqWithGroup_source; - this.seqWithEmptyGroup_source = seqWithEmptyGroup_source; - this.seqWithEmptySeq_source = seqWithEmptySeq_source; - - this.groupEmpty_source = groupEmpty_source; - this.groupSimple_source = groupSimple_source; - this.groupWithSeq_source = groupWithSeq_source; - this.groupWithGroup_source = groupWithGroup_source; - this.groupWithEmptyGroup_source = groupWithEmptyGroup_source; - this.groupWithEmptySeq_source = groupWithEmptySeq_source; - - this.staticAnimation = function(target, value, duration) { - var animation = new Animation(target, [{marginLeft: value}, {marginLeft: value}], duration); - animation.testValue = value; - return animation; - }; - // The following animation structure looks like: - // 44444 - // 11 - // 33 - // 2 - // 0 - this.complexTarget = document.createElement('div'); - this.elements.push(this.complexTarget); - this.complexSource = new AnimationGroup([ - this.staticAnimation(this.complexTarget, '4px', 5), - new AnimationSequence([ - this.staticAnimation(this.complexTarget, '1px', 2), - new AnimationGroup([ - this.staticAnimation(this.complexTarget, '3px', 2), - this.staticAnimation(this.complexTarget, '2px', 1), - ]), - ]), - this.staticAnimation(this.complexTarget, '0px', 1), - ]); - - this.target = document.createElement('div'); - this.elements.push(this.target); - - for (var i = 0; i < this.elements.length; i++) - document.documentElement.appendChild(this.elements[i]); - }); - - teardown(function() { - for (var i = 0; i < this.elements.length; i++) { - if (this.elements[i].parent) - this.elements[i].parent.removeChild(this.elements[i]); - } - }); - - function simpleAnimationGroup() { - return new AnimationGroup([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]); - } - - function simpleAnimationSequence() { - return new AnimationSequence([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]); - } - - // FIXME: Remove _startOffset. - // playerState is [startTime, currentTime, _startOffset?, offset?] - // innerPlayerStates is a nested array tree of playerStates e.g. [[0, 0], [[1, -1], [2, -2]]] - function checkTimes(player, playerState, innerPlayerStates, description) { - description = description ? (description + ' ') : ''; - _checkTimes(player, playerState, 0, description + 'top player'); - _checkTimes(player, innerPlayerStates, 0, description + 'inner player'); - } - - function _checkTimes(player, timingList, index, trace) { - assert.isDefined(player, trace + ' exists'); - if (timingList.length == 0) { - assert.equal(player._childAnimations.length, index, trace + ' no remaining players'); - return; - } - if (timingList[0] === null || typeof timingList[0] == 'number') { - assert.equal(player.startTime, timingList[0], trace + ' startTime'); - assert.equal(player.currentTime, timingList[1], trace + ' currentTime'); - } else { - _checkTimes(player._childAnimations[index], timingList[0], 0, trace + ' ' + index); - _checkTimes(player, timingList.slice(1), index + 1, trace); - } - } - - test('playing an animationGroup works as expected', function() { - tick(90); - var p = document.timeline.play(simpleAnimationGroup()); - checkTimes(p, [null, 0], [[null, 0], [null, 0], [null, 0]]); - tick(100); - checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]); - tick(300); - checkTimes(p, [100, 200], [[100, 200], [100, 200], [100, 200]]); - tick(1200); - checkTimes(p, [100, 1100], [[100, 1100], [100, 1000], [100, 1100]]); - tick(2200); - checkTimes(p, [100, 2100], [[100, 2000], [100, 1000], [100, 2100]]); - tick(3200); - checkTimes(p, [100, 3000], [[100, 2000], [100, 1000], [100, 3000]]); - }); - - test('can seek an animationGroup', function() { - tick(90); - var p = document.timeline.play(simpleAnimationGroup()); - tick(100); - checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]); - p.currentTime = 200; - checkTimes(p, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]); - p.currentTime = 1100; - checkTimes(p, [-1000, 1100], [[-1000, 1100], [-1000, 1100], [-1000, 1100]]); - p.currentTime = 2100; - checkTimes(p, [-2000, 2100], [[-2000, 2100], [-2000, 2100], [-2000, 2100]]); - p.currentTime = 3100; - checkTimes(p, [-3000, 3100], [[-3000, 3100], [-3000, 3100], [-3000, 3100]]); - }); - - test('can startTime seek an animationGroup', function() { - tick(90); - var p = document.timeline.play(simpleAnimationGroup()); - tick(100); - checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]); - p.startTime = -100; - checkTimes(p, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]); - p.startTime = -1000; - checkTimes(p, [-1000, 1100], [[-1000, 1100], [-1000, 1000], [-1000, 1100]]); - p.startTime = -2000; - checkTimes(p, [-2000, 2100], [[-2000, 2000], [-2000, 1000], [-2000, 2100]]); - p.startTime = -3000; - checkTimes(p, [-3000, 3000], [[-3000, 2000], [-3000, 1000], [-3000, 3000]]); - }); - - test('playing an animationSequence works as expected', function() { - tick(100); - var p = document.timeline.play(simpleAnimationSequence()); - tick(110); - checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); - tick(210); - checkTimes(p, [110, 100], [[110, 100], [2110, -1900], [3110, -2900]]); - tick(2210); - checkTimes(p, [110, 2100], [[110, 2000], [2110, 100], [3110, -900]]); - tick(3210); - checkTimes(p, [110, 3100], [[110, 2000], [2110, 1000], [3110, 100]]); - tick(6210); - checkTimes(p, [110, 6000], [[110, 2000], [2110, 1000], [3110, 3000]]); - }); - - test('can seek an animationSequence', function() { - tick(100); - var p = document.timeline.play(simpleAnimationSequence()); - tick(110); - checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); - p.currentTime = 100; - checkTimes(p, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]); - p.currentTime = 2100; - checkTimes(p, [-1990, 2100], [[-1990, 2100], [10, 100], [1010, -900]]); - p.currentTime = 3100; - checkTimes(p, [-2990, 3100], [[-2990, 3100], [-990, 1100], [10, 100]]); - p.currentTime = 6100; - checkTimes(p, [-5990, 6100], [[-5990, 6100], [-3990, 4100], [-2990, 3100]]); - }); - - test('can startTime seek an animationSequence', function() { - tick(100); - var p = document.timeline.play(simpleAnimationSequence()); - tick(110); - checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]); - p.startTime = 10; - checkTimes(p, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]); - p.startTime = -1990; - checkTimes(p, [-1990, 2100], [[-1990, 2000], [10, 100], [1010, -900]]); - p.startTime = -2990; - checkTimes(p, [-2990, 3100], [[-2990, 2000], [-990, 1000], [10, 100]]); - p.startTime = -5990; - checkTimes(p, [-5990, 6000], [[-5990, 2000], [-3990, 1000], [-2990, 3000]]); - }); - - test('complex animation tree timing while playing', function() { - tick(90); - var player = document.timeline.play(this.complexSource); - tick(100); - checkTimes(player, [100, 0], [ - [100, 0], [ // 4 - [100, 0], [ // 1 - [102, -2], // 3 - [102, -2]]], // 2 - [100, 0], // 0 - ], 't = 100'); - tick(101); - checkTimes(player, [100, 1], [ - [100, 1], [ // 4 - [100, 1], [ // 1 - [102, -1], // 3 - [102, -1]]], // 2 - [100, 1], // 0 - ], 't = 101'); - tick(102); - checkTimes(player, [100, 2], [ - [100, 2], [ // 4 - [100, 2], [ // 1 - [102, 0], // 3 - [102, 0]]], // 2 - [100, 1], // 0 - ], 't = 102'); - }); - - test('effects apply in the correct order', function() { - tick(0); - var player = document.timeline.play(this.complexSource); - player.currentTime = 0; - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); - player.currentTime = 1; - checkTimes(player, [-1, 1], [[-1, 1, 0], [[-1, 1, 0], [[1, -1, 0], [1, -1, 0]]], [-1, 1, 0]]); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '1px'); - player.currentTime = 2; - // TODO: When we seek we don't limit. Is this OK? - checkTimes(player, [-2, 2], [[-2, 2, 0], [[-2, 2, 0], [[0, 0, 0], [0, 0, 0]]], [-2, 2, 0]]); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '2px'); - player.currentTime = 3; - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px'); - player.currentTime = 4; - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '4px'); - player.currentTime = 5; - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); - }); - - test('cancelling group players', function() { - tick(0); - var player = document.timeline.play(this.complexSource); - tick(1); - tick(4); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px'); - player.cancel(); - assert.equal(player.currentTime, null); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); - }); - - test('cancelling group players before tick', function() { - tick(0); - var player = document.timeline.play(this.complexSource); - player.cancel(); - assert.equal(player.currentTime, null); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); - tick(4); - assert.equal(player.currentTime, null); - assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px'); - }); - - test('redundant animation node wrapping', function() { - tick(100); - var animation = new AnimationSequence([ - this.staticAnimation(this.target, '0px', 1), - new AnimationGroup([ - new AnimationSequence([ - this.staticAnimation(this.target, '1px', 1), - this.staticAnimation(this.target, '2px', 1), - ]), - ]), - ]); - var player = document.timeline.play(animation); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - checkTimes(player, [100, 0], [ - [100, 0, 0, 0], [[ // 0 - [101, -1, 0, 1], // 1 - [102, -2, 1, 2]]] // 2 - ], 't = 100'); - tick(101); - assert.equal(getComputedStyle(this.target).marginLeft, '1px'); - checkTimes(player, [100, 1], [ - [100, 1, 0, 0], [[ // 0 - [101, 0, 0, 1], // 1 - [102, -1, 1, 2]]] // 2 - ], 't = 101'); - tick(102); - assert.equal(getComputedStyle(this.target).marginLeft, '2px'); - assert.equal(document.timeline.currentTime, 102); - checkTimes(player, [100, 2], [ // FIXME: Implement limiting on group players - [100, 1, 0, 0], [[ // 0 - [101, 1, 0, 1], // 1 - [102, 0, 1, 2]]] // 2 - ], 't = 102'); - tick(103); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - checkTimes(player, [100, 3], [ // FIXME: Implement limiting on group players - [100, 1, 0, 0], [[ // 0 - [101, 1, 0, 1], // 1 - [102, 1, 1, 2]]] // 2 - ], 't = 103'); - if (this.target.parent) - this.target.parent.removeChild(target); - }); - - test('setting the playbackRate on group players', function() { - var group = new AnimationGroup([ - new Animation(null, [], 1234), - new Animation(null, [], 1234), - ]); - var p = document.timeline.play(group); - p.playbackRate = 2; - assert.equal(p._animation.playbackRate, 2, 'Updates the playbackRate of the inner player'); - p._childAnimations.forEach(function(childPlayer) { - assert.equal(childPlayer.playbackRate, 2, 'It also updates the child players'); - }); - }); - - test('delays on groups work correctly', function() { - // 444 - // 1 - // 0 - // 33 - // 2 - var animation = new AnimationGroup([ - new AnimationGroup([ - this.staticAnimation(this.target, '4px', {duration: 3, delay: 1}), - this.staticAnimation(this.target, '1px', {duration: 1, delay: 0}), - ], {delay: 1}), - new AnimationSequence([ - this.staticAnimation(this.target, '0px', {duration: 1, delay: 0}), - this.staticAnimation(this.target, '3px', {duration: 2, delay: 1}), - this.staticAnimation(this.target, '2px', {duration: 1, delay: -2}), - ]), - ]); - var player = document.timeline.play(animation); - tick(100); - checkTimes(player, [100, 0], [ - [ - [101, -1], - [101, -1], - ], [ - [100, 0], - [101, -1], - [104, -4], - ] - ]); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - tick(101); - assert.equal(getComputedStyle(this.target).marginLeft, '1px'); - tick(102); - assert.equal(getComputedStyle(this.target).marginLeft, '2px'); - tick(103); - assert.equal(getComputedStyle(this.target).marginLeft, '3px'); - tick(104); - assert.equal(getComputedStyle(this.target).marginLeft, '4px'); - tick(105); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - }); - - test('end delays on groups work correctly', function() { - // 11 - // 4 - // 0 - // 33 - // 2 - var animation = new AnimationSequence([ - new AnimationSequence([ - this.staticAnimation(this.target, '1px', {duration: 2, endDelay: 2}), - this.staticAnimation(this.target, '4px', {duration: 1, endDelay: 1}), - ], {endDelay: -6}), - new AnimationSequence([ - this.staticAnimation(this.target, '0px', {duration: 1, endDelay: 1}), - this.staticAnimation(this.target, '3px', {duration: 2, endDelay: -2}), - this.staticAnimation(this.target, '2px', {duration: 1, endDelay: 2}), - ]), - ]); - var player = document.timeline.play(animation); - tick(100); - checkTimes(player, [100, 0], [ - [ - [100, 0], - [104, -4], - ], [ - [100, 0], - [102, -2], - [102, -2], - ] - ]); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - tick(101); - assert.equal(getComputedStyle(this.target).marginLeft, '1px'); - tick(102); - assert.equal(getComputedStyle(this.target).marginLeft, '2px'); - tick(103); - assert.equal(getComputedStyle(this.target).marginLeft, '3px'); - tick(104); - // FIXME: Group child player limiting bounds should match the parent player's limiting bounds. - // assert.equal(getComputedStyle(this.target).marginLeft, '4px'); - // tick(105); - // assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - }); - - // FIXME: This test can be removed when this suite is finished. - test('sources are working for basic operations', function() { - var players = []; - players.push(document.timeline.play(this.seqEmpty_source)); - players.push(document.timeline.play(this.seqSimple_source)); - players.push(document.timeline.play(this.seqWithSeq_source)); - players.push(document.timeline.play(this.seqWithGroup_source)); - players.push(document.timeline.play(this.seqWithEmptyGroup_source)); - players.push(document.timeline.play(this.seqWithEmptySeq_source)); - - players.push(document.timeline.play(this.groupEmpty_source)); - players.push(document.timeline.play(this.groupSimple_source)); - players.push(document.timeline.play(this.groupWithSeq_source)); - players.push(document.timeline.play(this.groupWithGroup_source)); - players.push(document.timeline.play(this.groupWithEmptyGroup_source)); - players.push(document.timeline.play(this.groupWithEmptySeq_source)); - - var length = players.length; - - tick(50); - for (var i = 0; i < length; i++) - players[i].pause(); - - tick(100); - for (var i = 0; i < length; i++) - players[i].play(); - - tick(200); - for (var i = 0; i < length; i++) - players[i].currentTime += 1; - - tick(300); - for (var i = 0; i < length; i++) - players[i].startTime += 1; - - tick(350); - for (var i = 0; i < length; i++) - players[i].reverse(); - - tick(400); - for (var i = 0; i < length; i++) - players[i].finish(); - - tick(500); - tick(600); - for (var i = 0; i < length; i++) - players[i].cancel(); - - for (var i = 0; i < length; i++) - players[i].play(); - }); - - test('pausing works as expected with an empty AnimationSequence', function() { - var player = document.timeline.play(this.seqEmpty_source); - tick(0); - assert.equal(player.startTime, 0); - assert.equal(player.currentTime, 0); - - player.pause(); - assert.equal(player.startTime, null); - assert.equal(player.currentTime, 0); - }); - - test('pausing works as expected with a simple AnimationSequence', function() { - var player = document.timeline.play(this.seqSimple_source); - var target = this.seqSimple_source.children[0].target; - tick(0); - checkTimes(player, [0, 0], [[0, 0], [500, -500]], 't = 0'); - - tick(200); - checkTimes(player, [0, 200], [[0, 200], [500, -300]], 't = 200'); - - player.pause(); - checkTimes(player, [null, null], [[null, null], [null, null]], 't = 200'); - assert.equal(getComputedStyle(target).marginLeft, '40px'); - - tick(300); - checkTimes(player, [null, 200], [[null, 200], [null, -300]], 't = 300'); - assert.equal(getComputedStyle(target).marginLeft, '40px'); - - player.play(); - checkTimes(player, [null, 200], [[null, 200], [null, -300]], 't = 300'); - assert.equal(getComputedStyle(target).marginLeft, '40px'); - - tick(301); - checkTimes(player, [101, 200], [[101, 200], [601, -300]], 't = 301'); - assert.equal(getComputedStyle(target).marginLeft, '40px'); - - tick(401); - checkTimes(player, [101, 300], [[101, 300], [601, -200]], 't = 401'); - assert.equal(getComputedStyle(target).marginLeft, '60px'); - - tick(700); - checkTimes(player, [101, 599], [[101, 500], [601, 99]], 't = 700'); - assert.equal(getComputedStyle(target).marginLeft, '0px'); - }); - - test('pausing before tick works as expected with a simple AnimationSequence', function() { - var player = document.timeline.play(this.seqSimple_source); - var target = this.seqSimple_source.children[0].target; - checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 0'); - - player.pause(); - checkTimes(player, [null, null], [[null, null], [null, null]], 't = 0'); - assert.equal(getComputedStyle(target).marginLeft, '0px'); - - tick(10); - checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10'); - assert.equal(getComputedStyle(target).marginLeft, '0px'); - - tick(20); - checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10'); - assert.equal(getComputedStyle(target).marginLeft, '0px'); - }); - - test('pausing and seeking before tick works as expected with a simple AnimationSequence', function() { - var player = document.timeline.play(this.seqSimple_source); - player.pause(); - - player.currentTime = 0; - checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10'); - - player.currentTime = 250; - checkTimes(player, [null, 250], [[null, 250], [null, -250]], 't = 10'); - - player.currentTime = 500; - checkTimes(player, [null, 500], [[null, 500], [null, 0]], 't = 10'); - - // FIXME: Expectation should be [null, 1000], [[null, 500], [null, 500]]. - player.currentTime = 1000; - checkTimes(player, [null, 1000], [[null, 1000], [null, 500]], 't = 10'); - }); - - test('pausing works as expected with an AnimationSequence inside an AnimationSequence', function() { - var player = document.timeline.play(this.seqWithSeq_source); - tick(0); - checkTimes( - player, - [0, 0], [ - [0, 0], - [500, -500], [ - [1000, -1000], - [1500, -1500]]], - 't = 0'); - - tick(200); - checkTimes( - player, - [0, 200], [ - [0, 200], - [500, -300], [ - [1000, -800], - [1500, -1300]]], - 't = 200'); - - player.pause(); - checkTimes( - player, - [null, null], [ - [null, null], - [null, null], [ - [null, null], - [null, null]]], - 't = 200'); - - tick(300); - checkTimes( - player, - [null, 200], [ - [null, 200], - [null, -300], [ - [null, -800], - [null, -1300]]], - 't = 300'); - - player.play(); - tick(310); - checkTimes( - player, - [110, 200], [ - [110, 200], - [610, -300], [ - [1110, -800], - [1610, -1300]]], - 't = 310'); - - tick(1300); - checkTimes( - player, - [110, 1190], [ - [110, 500], - [610, 500], [ - [1110, 190], - [1610, -310]]], - 't = 1300'); - - player.pause(); - checkTimes( - player, - [null, null], [ - [null, 500], - [null, 500], [ - [null, null], - [null, null]]], - 't = 1300'); - - tick(1400); - checkTimes( - player, - [null, 1190], [ - [null, 500], - [null, 500], [ - [null, 190], - [null, -310]]], - 't = 1400'); - - player.play(); - checkTimes( - player, - [null, 1190], [ - [null, 500], - [null, 500], [ - [null, 190], - [null, -310]]], - 't = 1400'); - - tick(1410); - checkTimes( - player, - [220, 1190], [ - [220, 500], - [720, 500], [ - [1220, 190], - [1720, -310]]], - 't = 1410'); - - tick(1600); - checkTimes( - player, - [220, 1380], [ - [220, 500], - [720, 500], [ - [1220, 380], - [1720, -120]]], - 't = 1600'); - - player.pause(); - checkTimes( - player, - [null, null], [ - [null, 500], - [null, 500], [ - [null, null], - [null, null]]], - 't = 1600'); - - tick(1700); - checkTimes( - player, - [null, 1380], [ - [null, 500], - [null, 500], [ - [null, 380], - [null, -120]]], - 't = 1700'); - - player.play(); - tick(1710); - checkTimes( - player, - [330, 1380], [ - [330, 500], - [830, 500], [ - [1330, 380], - [1830, -120]]], - 't = 1710'); - - tick(2400); - checkTimes( - player, - [330, 2000], [ - [330, 500], - [830, 500], [ - [1330, 500], - [1830, 500]]], - 't = 2400'); - }); - - test('pausing works as expected with an AnimationGroup inside an AnimationSequence', function() { - var player = document.timeline.play(this.seqWithGroup_source); - tick(0); - checkTimes( - player, - [0, 0], [ - [0, 0], - [500, -500], [ - [1000, -1000], - [1000, -1000]]], - 't = 0'); - - tick(200); - checkTimes( - player, - [0, 200], [ - [0, 200], - [500, -300], [ - [1000, -800], - [1000, -800]]], - 't = 200'); - - player.pause(); - checkTimes( - player, - [null, null], [ - [null, null], - [null, null], [ - [null, null], - [null, null]]], - 't = 200'); - - tick(300); - checkTimes( - player, - [null, 200], [ - [null, 200], - [null, -300], [ - [null, -800], - [null, -800]]], - 't = 300'); - - player.play(); - tick(310); - checkTimes( - player, - [110, 200], [ - [110, 200], - [610, -300], [ - [1110, -800], - [1110, -800]]], - 't = 310'); - - tick(1310); - checkTimes( - player, - [110, 1200], [ - [110, 500], - [610, 500], [ - [1110, 200], - [1110, 200]]], - 't = 1310'); - - player.pause(); - checkTimes( - player, - [null, null], [ - [null, 500], - [null, 500], [ - [null, null], - [null, null]]], - 't = 1310'); - - tick(1400); - checkTimes( - player, - [null, 1200], [ - [null, 500], - [null, 500], [ - [null, 200], - [null, 200]]], - 't = 1410'); - - player.play(); - tick(1410); - checkTimes( - player, - [210, 1200], [ - [210, 500], - [710, 500], [ - [1210, 200], - [1210, 200]]], - 't = 1410'); - - tick(1610); - checkTimes( - player, - [210, 1400], [ - [210, 500], - [710, 500], [ - [1210, 400], - [1210, 400]]], - 't = 1610'); - - player.pause(); - tick(1810); - checkTimes( - player, - [null, 1400], [ - [null, 500], - [null, 500], [ - [null, 400], - [null, 400]]], - 't = 1810'); - - player.play(); - tick(1820); - checkTimes( - player, - [420, 1400], [ - [420, 500], - [920, 500], [ - [1420, 400], - [1420, 400]]], - 't = 1820'); - - tick(2020); - checkTimes( - player, - [420, 1500], [ - [420, 500], - [920, 500], [ - [1420, 500], - [1420, 500]]], - 't = 2020'); - - player.pause(); - checkTimes( - player, - [null, 1500], [ - [null, 500], - [null, 500], [ - [null, 500], - [null, 500]]], - 't = 2020'); - }); - - test('pausing works as expected with an empty AnimationSequence inside an AnimationSequence', function() { - var player = document.timeline.play(this.seqWithEmptySeq_source); - tick(0); - checkTimes( - player, - [0, 0], [0, 0], - 't = 0'); - - player.pause(); - checkTimes( - player, - [null, 0], [null, 0], - 't = 0 after pause'); - }); - - test('pausing works as expected with an empty AnimationGroup inside an AnimationSequence', function() { - var player = document.timeline.play(this.seqWithEmptyGroup_source); - tick(0); - checkTimes( - player, - [0, 0], [0, 0], - 't = 0'); - - player.pause(); - checkTimes( - player, - [null, 0], [null, 0], - 't = 0 after pause'); - }); - - test('playState works for groups', function() { - var target = document.createElement('div'); - document.body.appendChild(target); - var anim = new AnimationSequence([new Animation(target, [], 100), new Animation(target, [], 100)]); - var p = document.timeline.play(anim); - assert.equal(p.playState, 'pending'); - tick(1); - assert.equal(p.playState, 'running'); - assert.equal(p._childAnimations[0]._animation.playState, 'running'); - assert.equal(p._childAnimations[1]._animation.playState, 'running'); - tick(101); - assert.equal(p.playState, 'running'); - assert.equal(p._childAnimations[0]._animation.playState, 'finished'); - assert.equal(p._childAnimations[1]._animation.playState, 'running'); - p.pause(); - assert.equal(p.playState, 'pending'); - assert.equal(p._childAnimations[0]._animation.playState, 'paused'); - assert.equal(p._childAnimations[1]._animation.playState, 'pending'); - tick(102); - assert.equal(p.playState, 'paused'); - assert.equal(p._childAnimations[0]._animation.playState, 'paused'); - assert.equal(p._childAnimations[1]._animation.playState, 'paused'); - p.play(); - assert.equal(p.playState, 'pending'); - assert.equal(p._childAnimations[0]._animation.playState, 'pending'); - assert.equal(p._childAnimations[1]._animation.playState, 'pending'); - tick(103); - assert.equal(p.playState, 'running'); - assert.equal(p._childAnimations[0]._animation.playState, 'finished'); - assert.equal(p._childAnimations[1]._animation.playState, 'running'); - tick(204); - assert.equal(p.playState, 'finished'); - assert.equal(p._childAnimations[0]._animation.playState, 'finished'); - assert.equal(p._childAnimations[1]._animation.playState, 'finished'); - }); - - test('pausing then seeking out of range then seeking into range works', function() { - var target = document.createElement('div'); - var anim = new Animation(target, [], {duration: 2000, fill: 'both'}); - var group = new AnimationGroup([anim], {fill: 'none'}); - var player = document.timeline.play(group); - - player.pause(); - player.currentTime = 3000; - assert.equal(player._childAnimations.length, 0); - tick(100); - player.currentTime = 1000; - assert.equal(player._childAnimations.length, 1); - assert.equal(player._childAnimations[0]._animation.playState, 'paused'); - assert.equal(player._childAnimations[0]._animation.currentTime, 1000); - - }); - - test('reversing then seeking out of range then seeking into range works', function() { - var target = document.createElement('div'); - var anim = new Animation(target, [], {duration: 2000, fill: 'both'}); - var group = new AnimationGroup([anim], {fill: 'none'}); - var player = document.timeline.play(group); - - player.currentTime = 1000; - tick(100); - player.reverse(); - tick(105); - player.currentTime = 3000; - assert.equal(player._childAnimations.length, 0); - tick(110); - player.currentTime = 1000; - assert.equal(player.playbackRate, -1); - assert.equal(player._childAnimations.length, 1); - assert.equal(player._childAnimations[0]._animation.playState, 'running'); - assert.equal(player._childAnimations[0]._animation.currentTime, 1000); - assert.equal(player._childAnimations[0]._animation.playbackRate, -1); - - }); - - test('fill none groups with fill none children do not fill', function() { - var anim = new Animation( - this.target, - [{marginLeft: '0px'}, {marginLeft: '100px'}], - {duration: 500, fill: 'none'}); - var group = new AnimationGroup([anim], {fill: 'none'}); - var player = document.timeline.play(group); - - tick(0); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - tick(250); - assert.equal(getComputedStyle(this.target).marginLeft, '50px'); - tick(501); - assert.equal(getComputedStyle(this.target).marginLeft, '0px'); - tick(502); - }); -}); diff --git a/test/js/keyframe-effect-constructor.js b/test/js/keyframe-effect-constructor.js new file mode 100644 index 0000000..2b7be6c --- /dev/null +++ b/test/js/keyframe-effect-constructor.js @@ -0,0 +1,80 @@ +suite('keyframe-effect-constructor', function() { + setup(function() { + document.timeline.getAnimations().forEach(function(animation) { + animation.cancel(); + }); + }); + + test('Playing a KeyframeEffect makes an Animation', function() { + var keyframeEffect = new KeyframeEffect(document.body, [], 1000); + assert.equal(document.body.getAnimations().length, 0); + + var animation = document.timeline.play(keyframeEffect); + tick(200); + assert.equal(document.body.getAnimations().length, 1); + + tick(1600); + assert.equal(document.body.getAnimations().length, 0); + }); + + test('Setting the timing function on a KeyframeEffect works', function() { + function leftAsNumber(target) { + left = getComputedStyle(target).left; + return Number(left.substring(0, left.length - 2)); + } + + var target1 = document.createElement('div'); + var target2 = document.createElement('div'); + target1.style.position = 'absolute'; + target2.style.position = 'absolute'; + document.body.appendChild(target1); + document.body.appendChild(target2); + + var keyframeEffect1 = new KeyframeEffect(target1, [{left: '0px'}, {left: '50px'}], 1000); + var keyframeEffect2 = new KeyframeEffect(target2, [{left: '0px'}, {left: '50px'}], {duration: 1000, easing: 'ease-in'}); + + var animation1 = document.timeline.play(keyframeEffect1); + var animation2 = document.timeline.play(keyframeEffect2); + + tick(0); + assert.equal(leftAsNumber(target1), 0); + assert.equal(leftAsNumber(target2), 0); + + tick(250); + assert.closeTo(leftAsNumber(target1), 12.5, 1); + assert.closeTo(leftAsNumber(target2), 4.65, 1); + + tick(500); + assert.closeTo(leftAsNumber(target1), 25, 1); + assert.closeTo(leftAsNumber(target2), 15.25, 1); + }); + + test('Timing is always converted to an AnimationEffectTiming', function() { + var target = document.createElement('div'); + document.body.appendChild(target); + + var keyframes = [{background: 'blue'}, {background: 'red'}]; + + var keyframeEffect = new KeyframeEffect(target, keyframes, 200); + assert.equal(keyframeEffect.timing.duration, 200); + + keyframeEffect = new KeyframeEffect(target, keyframes); + assert.isDefined(keyframeEffect.timing); + + keyframeEffect = new KeyframeEffect(target, keyframes, {duration: 200}); + var group = new GroupEffect([keyframeEffect]); + assert.equal(group.timing.duration, 'auto'); + }); + + test('Handle null target for KeyframeEffect', function() { + var keyframeEffect = new KeyframeEffect(null, function(tf) { + // noop + }, 200); + + var animation = document.timeline.play(keyframeEffect); + assert.isNotNull(animation); + tick(50); + tick(150); + assert.equal(animation.currentTime, 100); + }); +}); diff --git a/test/js/matrix-interpolation.js b/test/js/matrix-interpolation.js index 4de36f7..8f8bb58 100644 --- a/test/js/matrix-interpolation.js +++ b/test/js/matrix-interpolation.js @@ -248,12 +248,12 @@ suite('matrix interpolation', function() { var target = document.createElement('div'); document.body.appendChild(target); - var player = target.animate( + var animation = target.animate( [{transform: 'translate(100px)'}, {transform: 'rotate(45deg)'}], 2000); - player.currentTime = 500; - player.pause(); + animation.currentTime = 500; + animation.pause(); var styleTransform = getComputedStyle(target).transform || getComputedStyle(target).webkitTransform; var elements = styleTransform.slice( diff --git a/test/js/player.js b/test/js/player.js deleted file mode 100644 index 2183848..0000000 --- a/test/js/player.js +++ /dev/null @@ -1,470 +0,0 @@ -suite('player', function() { - setup(function() { - webAnimations1.timeline._animations = []; - }); - test('zero duration animation works', function() { - tick(90); - var p = document.body.animate([], 0); - tick(100); - assert.equal(p.startTime, 100); - assert.equal(p.currentTime, 0); - }); - test('playing works as expected', function() { - tick(90); - var p = document.body.animate([], 2000); - tick(100); - assert.equal(p.startTime, 100); - assert.equal(p.currentTime, 0); - tick(300); - assert.equal(p.startTime, 100); - assert.equal(p.currentTime, 200); - }); - test('pause at start of play', function() { - tick(90); - var p = document.body.animate([], 2000); - p.pause(); - tick(100); - assert.equal(p.currentTime, 0); - tick(300); - p.play(); - assert.equal(p.currentTime, 0); - tick(310); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 310); - - var p = document.body.animate([], 2000); - p.startTime = -690; - p.pause(); - assert.equal(p.currentTime, null); - tick(700); - p.play(); - tick(701); - assert.equal(p.currentTime, 1000); - tick(800); - assert.equal(p.currentTime, 1099); - assert.equal(p.startTime, -299); - }); - test('pausing works as expected', function() { - tick(190); - var p = document.body.animate([], 3000); - tick(200); - tick(1500); - assert.equal(p.startTime, 200); - assert.equal(p.currentTime, 1300); - p.pause(); - assert.equal(p.startTime, null); - assert.equal(p.currentTime, null); - tick(2500); - assert.equal(p.startTime, null); - assert.equal(p.currentTime, 1300); - p.play(); - tick(2510); - assert.equal(p.startTime, 1210); - assert.equal(p.currentTime, 1300); - tick(3500); - assert.equal(p.startTime, 1210); - assert.equal(p.currentTime, 2290); - }); - test('reversing works as expected', function() { - tick(290); - var p = document.body.animate([], 1000); - tick(300); - assert.equal(p.startTime, 300); - assert.equal(p.currentTime, 0); - tick(600); - assert.equal(p.startTime, 300); - assert.equal(p.currentTime, 300); - assert.equal(p.playbackRate, 1); - p.reverse(); - tick(600); - assert.equal(p.startTime, 900); - assert.equal(p.currentTime, 300); - assert.equal(p.playbackRate, -1); - tick(700); - assert.equal(p.startTime, 900); - assert.equal(p.currentTime, 200); - }); - test('reversing after pausing', function() { - tick(90); - var p = document.body.animate([], 1000); - tick(100); - tick(600); - p.reverse(); - tick(601); - tick(700); - assert.equal(p.startTime, 1101); - assert.equal(p.currentTime, 401); - }); - test('reversing after finishing works as expected', function() { - tick(90); - var p = document.body.animate([], 1000); - tick(100); - tick(1200); - assert.equal(p.finished, true); - assert.equal(p.startTime, 100); - assert.equal(p.currentTime, 1000); - tick(1500); - assert.equal(p.currentTime, 1000); - assert.equal(isTicking(), false); - p.reverse(); - assert.equal(p._startTime, null); - assert.equal(p.currentTime, 1000); - tick(1600); - assert.equal(p.startTime, 2600); - assert.equal(p.currentTime, 1000); - }); - test('playing after finishing works as expected', function() { - tick(90); - var p = document.body.animate([], 1000); - tick(100); - tick(1200); - assert.equal(p.finished, true); - assert.equal(p.startTime, 100); - assert.equal(p.currentTime, 1000); - tick(1500); - assert.equal(p.currentTime, 1000); - assert.equal(isTicking(), false); - p.play(); - assert.equal(p.startTime, null); - assert.equal(p.currentTime, 0); - tick(1600); - assert.equal(p.startTime, 1600); - assert.equal(p.currentTime, 0); - }); - test('limiting works as expected', function() { - tick(390); - var p = document.body.animate([], 1000); - tick(400); - assert.equal(p.startTime, 400); - assert.equal(p.currentTime, 0); - tick(900); - assert.equal(p.startTime, 400); - assert.equal(p.currentTime, 500); - tick(1400); - assert.equal(p.startTime, 400); - assert.equal(p.currentTime, 1000); - tick(1500); - assert.equal(p.startTime, 400); - assert.equal(p.currentTime, 1000); - p.reverse(); - assert.equal(p.playbackRate, -1); - assert.equal(p.currentTime, 1000); - assert.equal(p._startTime, null); - tick(2000); - assert.equal(p.currentTime, 1000); - assert.equal(p.startTime, 3000); - tick(2200); - assert.equal(p.currentTime, 800); - assert.equal(p.startTime, 3000); - tick(3200); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 3000); - tick(3500); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 3000); - }); - test('play after limit works as expected', function() { - tick(490); - var p = document.body.animate([], 2000); - tick(500); - tick(2600); - assert.equal(p.currentTime, 2000); - assert.equal(p.startTime, 500); - assert.equal(p.finished, true); - assert.equal(p.playbackRate, 1); - setTicking(true); - p.play(); - tick(2700); - assert.equal(p.startTime, 2700); - assert.equal(p.currentTime, 0); - assert.equal(p.finished, false); - assert.equal(p.playbackRate, 1); - }); - test('play after limit works as expected (reversed)', function() { - tick(590); - var p = document.body.animate([], 3000); - tick(600); - tick(700); - p.reverse(); - tick(701); - tick(900); - assert.equal(p.startTime, 801); - assert.equal(p.currentTime, 0); - assert.equal(p.finished, true); - assert.equal(p.playbackRate, -1); - setTicking(true); - p.play(); - tick(1000); - assert.equal(p.startTime, 4000); - assert.equal(p.currentTime, 3000); - assert.equal(p.finished, false); - assert.equal(p.playbackRate, -1); - }); - test('seeking works as expected', function() { - tick(690); - var p = document.body.animate([], 2000); - tick(700); - tick(900); - assert.equal(p.currentTime, 200); - p.currentTime = 600; - assert.equal(p.currentTime, 600); - assert.equal(p.startTime, 300); - p.reverse(); - tick(1000); - assert.equal(p.startTime, 1600); - p.currentTime = 300; - assert.equal(p.currentTime, 300); - assert.equal(p.startTime, 1300); - }); - test('seeking while paused works as expected', function() { - tick(790); - var p = document.body.animate([], 1000); - tick(800); - tick(1000); - p.pause(); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - assert.equal(p.paused, true); - p.currentTime = 500; - assert.equal(p.startTime, null); - assert.equal(p.paused, true); - }); - test('setting start time while paused is ignored', function() { - tick(900); - var p = document.body.animate([], 1234); - p.pause(); - assert.equal(p.startTime, null); - assert.equal(p.currentTime, null); - p.startTime = 2232; - assert.equal(p.startTime, null); - assert.equal(p.currentTime, null); - }); - test('setting playbackRate does preserves the current time', function() { - tick(900); - var p = document.body.animate([], 1000); - tick(1100); - var oldCurrentTime = p.currentTime; - p.playbackRate = 2; - assert.equal(p.playbackRate, 2); - assert.equal(p.currentTime, oldCurrentTime); - }); - test('finishing works as expected', function() { - tick(1000); - var p = document.body.animate([], 2000); - p.finish(); - assert.equal(p.startTime, 0); - assert.equal(p.currentTime, 2000); - p.reverse(); - p.finish(); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 2000); - tick(2000); - }); - test('cancelling clears all effects', function() { - tick(0); - var target = document.createElement('div'); - document.documentElement.appendChild(target); - var player = target.animate([{marginLeft: '50px'}, {marginLeft: '50px'}], 1000); - tick(10); - tick(110); - assert.equal(getComputedStyle(target).marginLeft, '50px'); - player.cancel(); - // getComputedStyle forces a tick. - assert.equal(getComputedStyle(target).marginLeft, '0px'); - assert.deepEqual(webAnimations1.timeline._animations, []); - tick(120); - assert.equal(getComputedStyle(target).marginLeft, '0px'); - assert.deepEqual(webAnimations1.timeline._animations, []); - document.documentElement.removeChild(target); - }); - test('startTime is set on first tick if timeline hasn\'t started', function() { - webAnimations1.timeline.currentTime = undefined; - var p = document.body.animate([], 1000); - tick(0); - tick(100); - assert.equal(p.startTime, 0); - }); - test('players which are finished and not filling get discarded', function() { - tick(90); - var nofill = document.body.animate([], 100); - var fill = document.body.animate([], {duration: 100, fill: 'forwards'}); - assert.deepEqual(webAnimations1.timeline._animations, [nofill._animation || nofill, fill._animation || fill]); - tick(100); - assert.deepEqual(webAnimations1.timeline._animations, [nofill._animation || nofill, fill._animation || fill]); - tick(400); - assert.deepEqual(webAnimations1.timeline._animations, [fill._animation || fill]); - }); - test('discarded players get re-added on modification', function() { - tick(90); - var player = document.body.animate([], 100); - tick(100); - tick(400); - assert.deepEqual(webAnimations1.timeline._animations, []); - player.currentTime = 0; - assert.deepEqual(webAnimations1.timeline._animations, [player._animation || player]); - }); - test('players in the before phase are not discarded', function() { - tick(100); - var player = document.body.animate([], 100); - player.currentTime = -50; - tick(110); - assert.deepEqual(webAnimations1.timeline._animations, [player._animation || player]); - }); - test('players that go out of effect should not clear the effect of players that are in effect', function() { - var target = document.createElement('div'); - document.body.appendChild(target); - tick(0); - var playerBehind = target.animate([{marginLeft: '200px'}, {marginLeft: '200px'}], 200); - var playerInfront = target.animate([{marginLeft: '100px'}, {marginLeft: '100px'}], 100); - tick(50); - assert.equal(getComputedStyle(target).marginLeft, '100px', 't = 50'); - tick(150); - assert.equal(getComputedStyle(target).marginLeft, '200px', 't = 150'); - tick(250); - assert.equal(getComputedStyle(target).marginLeft, '0px', 't = 250'); - document.body.removeChild(target); - }); - test('player modifications should update CSS effects immediately', function() { - var target = document.createElement('div'); - document.body.appendChild(target); - tick(0); - var playerBehind = target.animate([{width: '1234px'}, {width: '1234px'}], {duration: 1, fill: 'both'}); - var playerInfront = target.animate([{width: '0px'}, {width: '100px'}], 100); - assert.equal(getComputedStyle(target).width, '0px'); - playerInfront.currentTime = 50; - assert.equal(getComputedStyle(target).width, '50px'); - playerInfront.currentTime = 100; - assert.equal(getComputedStyle(target).width, '1234px'); - playerInfront.play(); - assert.equal(getComputedStyle(target).width, '0px'); - playerInfront.startTime = -50; - assert.equal(getComputedStyle(target).width, '50px'); - document.body.removeChild(target); - }); - test('Player that hasn\'t been played has playState \'idle\'', function() { - var source = new webAnimations1Animation(document.body, [], 1000); - var p = new Player(source); - assert.equal(p.playState, 'idle'); - }); - test('playState works for a simple animation', function() { - var p = document.body.animate([], 1000); - tick(0); - assert.equal(p.playState, 'running'); - tick(100); - assert.equal(p.playState, 'running'); - p.pause(); - assert.equal(p.playState, 'pending'); - tick(101); - assert.equal(p.playState, 'paused'); - p.play(); - assert.equal(p.playState, 'pending'); - tick(102); - assert.equal(p.playState, 'running'); - tick(1002); - assert.equal(p.playState, 'finished'); - }); - test('Play after cancel', function() { - var p = document.body.animate([], 1000); - assert.equal(p.playState, 'pending'); - tick(0); - p.cancel(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - tick(1); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - p.play(); - assert.equal(p.playState, 'pending'); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, null); - tick(10); - assert.equal(p.playState, 'running'); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 10); - }); - test('Reverse after cancel', function() { - var p = document.body.animate([], 300); - tick(0); - p.cancel(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - tick(1); - p.reverse(); - assert.equal(p.playState, 'pending'); - assert.equal(p.currentTime, 300); - assert.equal(p.startTime, null); - tick(100); - assert.equal(p.playState, 'running'); - assert.equal(p.currentTime, 300); - assert.equal(p.startTime, 400); - tick(300); - assert.equal(p.playState, 'running'); - assert.equal(p.currentTime, 100); - assert.equal(p.startTime, 400); - tick(400); - assert.equal(p.playState, 'finished'); - assert.equal(p.currentTime, 0); - assert.equal(p.startTime, 400); - }); - test('Finish after cancel', function() { - var p = document.body.animate([], 300); - tick(0); - p.cancel(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - tick(1); - p.finish(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - tick(2); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - }); - test('Pause after cancel', function() { - var p = document.body.animate([], 300); - tick(0); - p.cancel(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - tick(1); - p.pause(); - assert.equal(p.playState, 'idle'); - assert.equal(p.currentTime, null); - assert.equal(p.startTime, null); - }); - test('Players ignore NaN times', function() { - var p = document.body.animate([], 300); - p.startTime = 100; - tick(110); - assert.equal(p.currentTime, 10); - p.startTime = NaN; - assert.equal(p.startTime, 100); - p.currentTime = undefined; - assert.equal(p.currentTime, 10); - }); - test('play() should not set a start time', function() { - var p = document.body.animate([], 1000); - p.cancel(); - assert.equal(p.startTime, null); - assert.equal(p.playState, 'idle'); - p.play(); - assert.equal(p.startTime, null); - assert.equal(p.playState, 'pending'); - }); - test('reverse() should not set a start time', function() { - var p = document.body.animate([], 1000); - p.cancel(); - assert.equal(p.startTime, null); - assert.equal(p.playState, 'idle'); - p.reverse(); - assert.equal(p.startTime, null); - assert.equal(p.playState, 'pending'); - }); -}); diff --git a/test/js/tick.js b/test/js/tick.js index 7c65788..1c42dd4 100644 --- a/test/js/tick.js +++ b/test/js/tick.js @@ -1,15 +1,15 @@ suite('tick-tests', function() { setup(function() { webAnimations1.timeline._animations = []; }); - test('players are in effect but ticking stops once forward fill is reached', function() { + test('animations are in effect but ticking stops once forward fill is reached', function() { tick(90); - var player = document.body.animate([], {duration: 1000, fill: 'forwards'}); + var animation = document.body.animate([], {duration: 1000, fill: 'forwards'}); tick(100); tick(600); assert.equal(webAnimations1.timeline._animations.length, 1); assert.equal(isTicking(), true); tick(1100); - assert.equal(player.finished, true); + assert.equal(animation.finished, true); assert.equal(webAnimations1.timeline._animations.length, 1); assert.equal(isTicking(), false); }); diff --git a/test/js/timeline.js b/test/js/timeline.js index 2875c58..9590ab7 100644 --- a/test/js/timeline.js +++ b/test/js/timeline.js @@ -4,21 +4,21 @@ suite('timeline-tests', function() { webAnimations1.timeline._animation = []; }); - test('no current players', function() { + test('no current animations', function() { assert.equal(document.timeline.getAnimations().length, 0); }); test('getAnimations', function() { tick(90); assert.equal(document.timeline.getAnimations().length, 0); - var player = document.body.animate([], {duration: 500, iterations: 1}); + var animation = document.body.animate([], {duration: 500, iterations: 1}); tick(300); assert.equal(document.timeline.getAnimations().length, 1); - var player2 = document.body.animate([], {duration: 1000}); + var animation2 = document.body.animate([], {duration: 1000}); assert.equal(document.timeline.getAnimations().length, 2); tick(800); - assert.equal(player.finished, true); + assert.equal(animation.finished, true); assert.equal(document.timeline.getAnimations().length, 1); tick(2000); assert.equal(document.timeline.getAnimations().length, 0); @@ -27,10 +27,10 @@ suite('timeline-tests', function() { test('getAnimations checks cancelled animation', function() { tick(90); assert.equal(document.timeline.getAnimations().length, 0); - var player = document.body.animate([], {duration: 500, iterations: 1}); + var animation = document.body.animate([], {duration: 500, iterations: 1}); tick(300); assert.equal(document.timeline.getAnimations().length, 1); - player.cancel(); + animation.cancel(); assert.equal(document.timeline.getAnimations().length, 0); }); }); diff --git a/test/js/timing.js b/test/js/timing.js index 3eab888..dae17d1 100644 --- a/test/js/timing.js +++ b/test/js/timing.js @@ -1,51 +1,47 @@ suite('timing', function() { - setup(function() { - webAnimations1.timeline._players = []; - }); - test('pause and scrub', function() { - var player = document.body.animate([], { duration: 1000 }); - player.pause(); + var animation = document.body.animate([], { duration: 1000 }); + animation.pause(); - player.currentTime = 500; - assert.equal(player.currentTime, 500); + animation.currentTime = 500; + assert.equal(animation.currentTime, 500); }); test('pause, scrub and play', function() { var target = document.createElement('div'); document.body.appendChild(target); - var player = target.animate([ + var animation = target.animate([ { background: 'blue' }, { background: 'red' } ], { duration: 1000 }); tick(100); - player.pause(); + animation.pause(); - player.currentTime = 200; - // http://www.w3.org/TR/web-animations/#the-current-time-of-a-player + animation.currentTime = 200; + // http://www.w3.org/TR/web-animations/#the-current-time-of-an-animation // currentTime should now mean 'hold time' - this allows scrubbing. - assert.equal(player.currentTime, 200); - player.play(); + assert.equal(animation.currentTime, 200); + animation.play(); tick(200); tick(300); - assert.equal(player.currentTime, 300); - assert.equal(player.startTime, 0); + assert.equal(animation.currentTime, 300); + assert.equal(animation.startTime, 0); }); test('sanity-check NaN timing', function() { // This has no actual tests, but will infinite loop without fix. - var player = document.body.animate([], { + var animation = document.body.animate([], { duration: 2000, easing: 'ease-in' // fails only with cubic easing, not linear }); tick(100); - player.currentTime = NaN; + animation.currentTime = NaN; tick(200); - player = document.body.animate([], { duration: NaN, easing: 'ease-out' }); + animation = document.body.animate([], { duration: NaN, easing: 'ease-out' }); tick(300); });