Bug 1302648 part 8 - Add animationcancel tests. r?birtles
MozReview-Commit-ID: 44nT8BBNgzT
--- a/dom/animation/test/css-animations/file_animation-cancel.html
+++ b/dom/animation/test/css-animations/file_animation-cancel.html
@@ -39,46 +39,29 @@ promise_test(function(t) {
assert_not_equals(getComputedStyle(div).transform, 'none',
'transform style is filling before cancelling');
animation.cancel();
assert_equals(getComputedStyle(div).transform, 'none',
'fill style is cleared after cancelling');
});
}, 'Animated style is cleared after cancelling a filling CSS animation');
-promise_test(function(t) {
- var div = addDiv(t, { style: 'animation: translateAnim 100s' });
- var animation = div.getAnimations()[0];
- div.addEventListener('animationend', t.step_func(function() {
- assert_unreached('Got unexpected end event on cancelled animation');
- }));
-
- return animation.ready.then(function() {
- // Seek to just before the end then cancel
- animation.currentTime = 99.9 * 1000;
- animation.cancel();
-
- // Then wait a couple of frames and check that no event was dispatched
- return waitForAnimationFrames(2);
- });
-}, 'Cancelled CSS animations do not dispatch events');
-
test(function(t) {
var div = addDiv(t, { style: 'animation: marginLeftAnim 100s linear' });
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is not animated after cancelling');
animation.currentTime = 50 * 1000;
assert_equals(getComputedStyle(div).marginLeft, '50px',
'margin-left style is updated when cancelled animation is'
+ ' seeked');
-}, 'After cancelling an animation, it can still be seeked');
+}, 'After canceling an animation, it can still be seeked');
promise_test(function(t) {
var div =
addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
var animation = div.getAnimations()[0];
return animation.ready.then(function() {
animation.cancel();
@@ -100,17 +83,16 @@ test(function(t) {
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is not animated after cancelling');
// Trigger a change to some animation properties and check that this
// doesn't cause the animation to become live again
div.style.animationDuration = '200s';
- flushComputedStyle(div);
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is still not animated after updating'
+ ' animation-duration');
assert_equals(animation.playState, 'idle',
'Animation is still idle after updating animation-duration');
}, 'After cancelling an animation, updating animation properties doesn\'t make'
+ ' it live again');
@@ -143,12 +125,67 @@ test(function(t) {
div.style.animationPlayState = 'running';
assert_equals(animation.playState, 'idle',
'Animation is still idle after re-setting'
+ ' animation-play-state: running');
}, 'After cancelling an animation, updating animation-play-state doesn\'t'
+ ' make it live again');
+promise_test(function(t) {
+ var div = addDiv(t, { style: 'animation: translateAnim 10s both' });
+ div.style.marginLeft = '0px';
+
+ var animation = div.getAnimations()[0];
+
+ return animation.ready.then(function() {
+ assert_equals(animation.playState, 'running');
+
+ div.style.animationName = 'none';
+ flushComputedStyle(div);
+ return waitForFrame();
+ }).then(function() {
+ assert_equals(animation.playState, 'idle');
+ assert_equals(getComputedStyle(div).marginLeft, '0px');
+ });
+}, 'Setting animation-name to \'none\' cancels the animation');
+
+promise_test(function(t) {
+ var div = addDiv(t, { style: 'animation: translateAnim 10s both' });
+ var animation = div.getAnimations()[0];
+
+ return animation.ready.then(function() {
+ assert_equals(animation.playState, 'running');
+
+ div.style.display = 'none';
+ return waitForFrame();
+ }).then(function() {
+ assert_equals(animation.playState, 'idle');
+ assert_equals(getComputedStyle(div).marginLeft, '0px');
+ });
+}, 'Setting display:none on an element cancel its animations');
+
+promise_test(function(t) {
+ var parentDiv = addDiv(t);
+ var childDiv = document.createElement('div');
+ parentDiv.appendChild(childDiv);
+
+ childDiv.setAttribute('style', 'animation: translateAnim 10s both');
+ flushComputedStyle(childDiv);
+
+ var animation = childDiv.getAnimations()[0];
+
+ return animation.ready.then(function() {
+ assert_equals(animation.playState, 'running');
+
+ parentDiv.style.display = 'none';
+ return waitForFrame();
+ }).then(function() {
+ assert_equals(animation.playState, 'idle');
+ assert_equals(getComputedStyle(childDiv).marginLeft, '0px');
+ });
+}, 'Setting display:none on an ancestor element cancels animations on ' +
+ 'descendants');
+
done();
</script>
</body>
</html>
--- a/dom/animation/test/css-animations/file_event-dispatch.html
+++ b/dom/animation/test/css-animations/file_event-dispatch.html
@@ -25,28 +25,33 @@ function AnimationEventHandler(target) {
this.animationstart = evt.elapsedTime;
}.bind(this);
this.target.onanimationiteration = function(evt) {
this.animationiteration = evt.elapsedTime;
}.bind(this);
this.target.onanimationend = function(evt) {
this.animationend = evt.elapsedTime;
}.bind(this);
+ this.target.onanimationcancel = function(evt) {
+ this.animationcancel = evt.elapsedTime;
+ }.bind(this);
}
AnimationEventHandler.prototype.clear = function() {
- this.animationstart = undefined;
+ this.animationstart = undefined;
this.animationiteration = undefined;
- this.animationend = undefined;
+ this.animationend = undefined;
+ this.animationcancel = undefined;
}
function setupAnimation(t, animationStyle) {
var div = addDiv(t, { style: "animation: " + animationStyle });
var watcher = new EventWatcher(t, div, [ 'animationstart',
'animationiteration',
- 'animationend' ]);
+ 'animationend',
+ 'animationcancel' ]);
var animation = div.getAnimations()[0];
return [animation, watcher, div];
}
promise_test(function(t) {
// Add 1ms delay to ensure that the delay is not included in the elapsedTime.
const [animation, watcher] = setupAnimation(t, 'anim 100s 1ms');
@@ -93,16 +98,54 @@ promise_test(function(t) {
return watcher.wait_for([ 'animationstart', 'animationend' ]);
}).then(function(evt) {
assert_equals(handler.animationstart, 0.0);
assert_equals(handler.animationend, 100.0);
});
}, 'Before -> After');
promise_test(function(t) {
+ const [animation, watcher, div] = setupAnimation(t, 'anim 100s paused');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ div.style.display = 'none';
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ assert_equals(evt.elapsedTime, 0.0);
+ });
+}, 'Active -> Idle, display: none');
+
+promise_test(function(t) {
+ const [animation, watcher, div] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ animation.currentTime = 100.0;
+ // Make idle
+ animation.timeline = null;
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ assert_times_equal(evt.elapsedTime, 0.1);
+ });
+}, 'Active -> Idle, setting Animation.timeline = null');
+
+promise_test(function(t) {
+ // we should NOT pause animation since calling cancel synchronously.
+ const [animation, watcher, div] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ animation.currentTime = 50.0;
+ animation.cancel();
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ assert_times_equal(evt.elapsedTime, 0.05);
+ });
+}, 'Active -> Idle, calling Animation.cancel()');
+
+promise_test(function(t) {
const [animation, watcher] =
setupAnimation(t, 'anim 100s 100s paused');
// Seek to Active phase.
animation.currentTime = 100 * MS_PER_SEC;
return watcher.wait_for('animationstart').then(function() {
// Seek to Before phase.
animation.currentTime = 0;
@@ -211,18 +254,18 @@ promise_test(function(t) {
promise_test(function(t) {
const [animation, watcher, div] =
setupAnimation(t, 'anim 100s paused');
return watcher.wait_for('animationstart').then(function(evt) {
// Seek to Idle phase.
div.style.display = 'none';
flushComputedStyle(div);
- // FIXME: bug 1302648: Add test for animationcancel event here.
-
+ return watcher.wait_for('animationcancel');
+ }).then(function() {
// Restart this animation.
div.style.display = '';
return watcher.wait_for('animationstart');
});
}, 'Active -> Idle -> Active: animationstart is fired by restarting animation');
promise_test(function(t) {
const [animation, watcher] =
@@ -245,12 +288,94 @@ promise_test(function(t) {
animation.currentTime = 100 * MS_PER_SEC - 1;
return watcher.wait_for('animationend');
}).then(function(evt) {
assert_equals(evt.elapsedTime, 0);
assert_equals(animation.playState, 'running'); // delay
});
}, 'Negative playbackRate sanity test(Before -> Active -> Before)');
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ animation.cancel();
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ animation.cancel();
+ // Then wait a couple of frames and check that no event was dispatched.
+ return waitForAnimationFrames(2);
+ });
+}, 'Call Animation.cancel after cancelling animation.');
+
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ animation.cancel();
+ animation.play();
+ return watcher.wait_for([ 'animationcancel',
+ 'animationstart' ]);
+ });
+}, 'Restart animation after cancelling animation immediately.');
+
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ animation.cancel();
+ animation.play();
+ animation.cancel();
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ // Then wait a couple of frames and check that no event was dispatched.
+ return waitForAnimationFrames(2);
+ });
+}, 'Call Animation.cancel after restarting animation immediately.');
+
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ animation.timeline = null;
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ animation.timeline = document.timeline;
+ animation.play();
+ return watcher.wait_for('animationstart');
+ });
+}, 'Set timeline and play transition after clearing the timeline.');
+
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ // Make idle
+ animation.cancel();
+ return watcher.wait_for('animationcancel');
+ }).then(function(evt) {
+ animation.effect = null;
+ // Then wait a couple of frames and check that no event was dispatched.
+ return waitForAnimationFrames(2);
+ });
+}, 'Set null target effect after cancelling the animation.');
+
+promise_test(function(t) {
+ const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+ return watcher.wait_for('animationstart').then(function(evt) {
+ animation.effect = null;
+ return watcher.wait_for('animationend');
+ }).then(function(evt) {
+ animation.cancel();
+ // Then wait a couple of frames and check that no event was dispatched.
+ return waitForAnimationFrames(2);
+ });
+}, 'Cancel the animation after clearing the target effect.');
+
done();
</script>
</body>
</html>