Bug 1150807 part 5 - Tests for Animation.cancel(); r=jwatt

This commit is contained in:
Brian Birtles 2015-04-27 08:53:19 +09:00
Родитель 7382c76c89
Коммит e2c7d46cdc
10 изменённых файлов: 511 добавлений и 17 удалений

Просмотреть файл

@ -573,7 +573,8 @@ function assert_records(expected, desc) {
// Test that starting a single animation that is cancelled by updating
// the animation-iteration-count property dispatches an added notification
// and then a removed notification.
addAsyncAnimTest("single_animation_cancelled_fill", aOptions, function*() {
addAsyncAnimTest("single_animation_cancelled_iteration_count",
aOptions, function*() {
// Start a short, repeated animation.
e.style = "animation: anim 0.5s infinite;";
@ -605,6 +606,44 @@ function assert_records(expected, desc) {
e.style = "";
});
// Test that starting a single animation that is cancelled by calling
// cancel() dispatches an added notification and then a removed
// notification.
addAsyncAnimTest("single_animation_cancelled_api", aOptions, function*() {
// Start a short, filled animation.
e.style = "animation: anim 100s forwards;";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield await_frame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Cancel the animation
animations[0].cancel();
// Wait for the single MutationRecord for the Animation removal to
// be delivered.
yield await_frame();
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
// Re-trigger the animation
animations[0].play();
yield await_frame();
// Wait for the single MutationRecord for the Animation (re-)addition to
// be delivered.
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
e.style = "";
});
// Test that updating an animation property dispatches a changed notification.
[
{ name: "duration", prop: "animationDuration", val: "200s" },

Просмотреть файл

@ -0,0 +1,164 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<div id="log"></div>
<style>
@keyframes translateAnim {
to { transform: translate(100px) }
}
@keyframes marginLeftAnim {
to { margin-left: 100px }
}
@keyframes marginLeftAnim100To200 {
from { margin-left: 100px }
to { margin-left: 200px }
}
</style>
<script>
'use strict';
async_test(function(t) {
var div = addDiv(t, { style: 'animation: translateAnim 100s' });
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
assert_not_equals(getComputedStyle(div).transform, 'none',
'transform style is animated before cancelling');
animation.cancel();
assert_equals(getComputedStyle(div).transform, 'none',
'transform style is no longer animated after cancelling');
t.done();
}));
}, 'Animated style is cleared after cancelling a running CSS animation');
async_test(function(t) {
var div = addDiv(t, { style: 'animation: translateAnim 100s forwards' });
var animation = div.getAnimations()[0];
animation.finish();
animation.ready.then(t.step_func(function() {
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');
t.done();
}));
}, 'Animated style is cleared after cancelling a filling CSS animation');
async_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');
}));
animation.ready.then(t.step_func(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);
})).then(t.step_func(function() {
t.done();
}));
}, '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');
async_test(function(t) {
var div =
addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is not animated after cancelling');
animation.play();
assert_equals(getComputedStyle(div).marginLeft, '100px',
'margin-left style is animated after re-starting animation');
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.playState, 'running',
'Animation succeeds in running after being re-started');
t.done();
}));
}, 'After cancelling an animation, it can still be re-used');
test(function(t) {
var div =
addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
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');
test(function(t) {
var div =
addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is not animated after cancelling');
// Make some changes to animation-play-state and check that the
// animation doesn't become live again. This is because it should be
// possible to cancel an animation from script such that all future
// changes to style are ignored.
// Redundant change
div.style.animationPlayState = 'running';
assert_equals(animation.playState, 'idle',
'Animation is still idle after a redundant change to'
+ ' animation-play-state');
// Pause
div.style.animationPlayState = 'paused';
assert_equals(animation.playState, 'idle',
'Animation is still idle after setting'
+ ' animation-play-state: paused');
// Play
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');
</script>
</html>

Просмотреть файл

@ -511,7 +511,7 @@ async_test(function(t) {
'animation has finished');
t.done();
}));
}, 'Test Animation.currentTime clamping');
}, 'Animation.currentTime clamping');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
@ -533,7 +533,17 @@ async_test(function(t) {
'animation running in reverse has finished and currentTime is zero');
t.done();
}));
}, 'Test Animation.currentTime clamping for reversed animation');
}, 'Animation.currentTime clamping for reversed animation');
test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
div.style.animation = 'anim 100s';
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(animation.currentTime, null,
'The currentTime of a cancelled animation should be null');
}, 'Animation.currentTime after cancelling');
</script>
</body>

Просмотреть файл

@ -140,13 +140,11 @@ async_test(function(t) {
animation.finished.then(t.step_func(function() {
assert_unreached('finished promise is fulfilled');
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
assert_not_equals(animation.finished, previousFinishedPromise,
'Finished promise should change after the original is ' +
'rejected');
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
assert_equals(animation.playState, 'idle',
'Animation is idle after animation was cancelled');
})).then(t.step_func(function() {
t.done();
}));
@ -174,13 +172,11 @@ async_test(function(t) {
animation.finished.then(t.step_func(function() {
assert_unreached('finished promise was fulfilled');
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
assert_not_equals(animation.finished, previousFinishedPromise,
'Finished promise should change after the original is ' +
'rejected');
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
assert_equals(animation.playState, 'idle',
'Animation is idle after animation was cancelled');
})).then(t.step_func(function() {
t.done();
}));
@ -192,6 +188,72 @@ async_test(function(t) {
}, 'finished promise is rejected when an animation is cancelled by changing ' +
'the animation property');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
var previousFinishedPromise = animation.finished;
// Set up listeners on finished promise
animation.finished.then(t.step_func(function() {
assert_unreached('finished promise was fulfilled');
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
assert_not_equals(animation.finished, previousFinishedPromise,
'Finished promise should change after the original is ' +
'rejected');
})).then(t.step_func(function() {
t.done();
}));
animation.cancel();
}, 'finished promise is rejected when an animation is cancelled by calling ' +
'cancel()');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
var previousFinishedPromise = animation.finished;
animation.currentTime = ANIM_DURATION;
animation.finished.then(t.step_func(function() {
animation.cancel();
assert_not_equals(animation.finished, previousFinishedPromise,
'A new finished promise should be created when'
+ ' cancelling a finished player');
})).then(t.step_func(function() {
t.done();
}));
}, 'cancelling an already-finished player replaces the finished promise');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.cancel();
// The spec says we still create a new finished promise and reject the old
// one even if we're already idle. That behavior might change, but for now
// test that we do that.
animation.finished.catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'finished promise is rejected with AbortError');
t.done();
}));
// Redundant call to cancel();
var previousFinishedPromise = animation.finished;
animation.cancel();
assert_not_equals(animation.finished, previousFinishedPromise,
'A redundant call to cancel() should still generate a new'
+ ' finished promise');
}, 'cancelling an idle player still replaces the finished promise');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
@ -286,5 +348,4 @@ async_test(function(t) {
}));
}, 'Test finished promise changes when animationPlayState set to running');
</script>

Просмотреть файл

@ -66,4 +66,24 @@ test(function(t) {
+ ' animation-play-state (got: ' + animation.playState + ')');
}, 'Animation.playState updates when resumed by setting style');
test(function(t) {
var div = addDiv(t);
div.style.animation = 'anim 1000s';
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(animation.playState, 'idle');
}, 'Animation returns correct playState when cancelled');
test(function(t) {
var div = addDiv(t);
div.style.animation = 'anim 1000s';
var animation = div.getAnimations()[0];
animation.cancel();
animation.currentTime = 50 * 1000;
assert_equals(animation.playState, 'paused',
'After seeking an idle animation, it is effectively paused');
}, 'After cancelling an animation, seeking it makes it paused');
</script>

Просмотреть файл

@ -96,8 +96,6 @@ async_test(function(t) {
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'ready promise is rejected with AbortError');
assert_equals(animation.playState, 'idle',
'Animation is idle after animation was cancelled');
})).then(t.step_func(function() {
t.done();
}));
@ -128,8 +126,6 @@ async_test(function(t) {
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'ready promise is rejected with AbortError');
assert_equals(animation.playState, 'idle',
'Animation is idle after animation was cancelled');
})).then(t.step_func(function() {
t.done();
}));
@ -141,6 +137,47 @@ async_test(function(t) {
}, 'ready promise is rejected when an animation is cancelled by updating'
+ ' the animation property');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = 'abc 100s';
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
assert_unreached('ready promise was fulfilled');
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'ready promise is rejected with AbortError');
})).then(t.step_func(function() {
t.done();
}));
animation.cancel();
}, 'ready promise is rejected when a play-pending animation is cancelled by'
+ ' calling cancel()');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = 'abc 100s';
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.pause();
// Set up listeners on pause-pending ready promise
animation.ready.then(t.step_func(function() {
assert_unreached('ready promise was fulfilled');
})).catch(t.step_func(function(err) {
assert_equals(err.name, 'AbortError',
'ready promise is rejected with AbortError');
})).then(t.step_func(function() {
t.done();
}));
animation.cancel();
}));
}, 'ready promise is rejected when a pause-pending animation is cancelled by'
+ ' calling cancel()');
async_test(function(t) {
var div = addDiv(t, { style: 'animation: abc 100s' });
var animation = div.getAnimations()[0];

Просмотреть файл

@ -539,7 +539,20 @@ async_test(function(t) {
})).then(function() {
t.done();
});
}, 'Animation.startTime after paused');
}, 'Animation.startTime after pausing');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
div.style.animation = 'anim 100s';
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.cancel();
assert_equals(animation.startTime, null,
'The startTime of a cancelled animation should be null');
t.done();
}));
}, 'Animation.startTime after cancelling');
</script>
</body>

Просмотреть файл

@ -250,4 +250,23 @@ test(function(t) {
+ ' duration changes');
}, 'getAnimations returns objects with the same identity');
test(function(t) {
var div = addDiv(t);
div.style.animation = 'anim1 100s';
assert_equals(div.getAnimations().length, 1,
'getAnimations returns an animation before cancelling');
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(div.getAnimations().length, 0,
'getAnimations does not return cancelled animations');
animation.play();
assert_equals(div.getAnimations().length, 1,
'getAnimations returns cancelled animations that have been re-started');
}, 'getAnimations for CSS Animations that are cancelled');
</script>

Просмотреть файл

@ -0,0 +1,129 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<div id="log"></div>
<script>
'use strict';
async_test(function(t) {
var div = addDiv(t, { style: 'margin-left: 0px' });
flushComputedStyle(div);
div.style.transition = 'margin-left 100s';
div.style.marginLeft = '1000px';
flushComputedStyle(div);
var animation = div.getAnimations()[0];
animation.ready.then(waitForFrame).then(t.step_func(function() {
assert_not_equals(getComputedStyle(div).marginLeft, '1000px',
'transform style is animated before cancelling');
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, div.style.marginLeft,
'transform style is no longer animated after cancelling');
t.done();
}));
}, 'Animated style is cleared after cancelling a running CSS transition');
async_test(function(t) {
var div = addDiv(t, { style: 'margin-left: 0px' });
flushComputedStyle(div);
div.style.transition = 'margin-left 100s';
div.style.marginLeft = '1000px';
flushComputedStyle(div);
div.addEventListener('transitionend', t.step_func(function() {
assert_unreached('Got unexpected end event on cancelled transition');
}));
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(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);
})).then(t.step_func(function() {
t.done();
}));
}, 'Cancelled CSS transitions do not dispatch events');
async_test(function(t) {
var div = addDiv(t, { style: 'margin-left: 0px' });
flushComputedStyle(div);
div.style.transition = 'margin-left 100s';
div.style.marginLeft = '1000px';
flushComputedStyle(div);
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '1000px',
'margin-left style is not animated after cancelling');
animation.play();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is animated after re-starting transition');
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.playState, 'running',
'Transition succeeds in running after being re-started');
t.done();
}));
}, 'After cancelling a transition, it can still be re-used');
async_test(function(t) {
var div = addDiv(t, { style: 'margin-left: 0px' });
flushComputedStyle(div);
div.style.transition = 'margin-left 100s';
div.style.marginLeft = '1000px';
flushComputedStyle(div);
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.finish();
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '1000px',
'margin-left style is not animated after cancelling');
animation.play();
assert_equals(getComputedStyle(div).marginLeft, '0px',
'margin-left style is animated after re-starting transition');
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.playState, 'running',
'Transition succeeds in running after being re-started');
t.done();
}));
}, 'After cancelling a finished transition, it can still be re-used');
test(function(t) {
var div = addDiv(t, { style: 'margin-left: 0px' });
flushComputedStyle(div);
div.style.transition = 'margin-left 100s';
div.style.marginLeft = '1000px';
flushComputedStyle(div);
var animation = div.getAnimations()[0];
animation.cancel();
assert_equals(getComputedStyle(div).marginLeft, '1000px',
'margin-left style is not animated after cancelling');
// Trigger a change to a transition property and check that this
// doesn't cause the animation to become live again
div.style.transitionDuration = '200s';
flushComputedStyle(div);
assert_equals(getComputedStyle(div).marginLeft, '1000px',
'margin-left style is still not animated after updating'
+ ' transition-duration');
assert_equals(animation.playState, 'idle',
'Transition is still idle after updating transition-duration');
}, 'After cancelling a transition, updating transition properties doesn\'t make'
+ ' it live again');
</script>
</html>

Просмотреть файл

@ -3,6 +3,7 @@ support-files =
testcommon.js
[css-animations/test_animations-dynamic-changes.html]
[css-animations/test_animation-cancel.html]
[css-animations/test_animation-currenttime.html]
[css-animations/test_animation-finish.html]
[css-animations/test_animation-finished.html]
@ -14,6 +15,7 @@ support-files =
[css-animations/test_effect-target.html]
[css-animations/test_element-get-animations.html]
skip-if = buildapp == 'mulet'
[css-transitions/test_animation-cancel.html]
[css-transitions/test_animation-currenttime.html]
[css-transitions/test_animation-finished.html]
[css-transitions/test_animation-pausing.html]