diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /testing/web-platform/tests/web-animations/timing-model | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'testing/web-platform/tests/web-animations/timing-model')
9 files changed, 2466 insertions, 0 deletions
diff --git a/testing/web-platform/tests/web-animations/timing-model/animation-effects/active-time.html b/testing/web-platform/tests/web-animations/timing-model/animation-effects/active-time.html new file mode 100644 index 000000000..bdaad08ed --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/active-time.html @@ -0,0 +1,142 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Active time tests</title> +<link rel="help" href="https://w3c.github.io/web-animations/#calculating-the-active-time"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function(t) { + var tests = [ { fill: 'none', progress: null }, + { fill: 'backwards', progress: 0 }, + { fill: 'forwards', progress: null }, + { fill: 'both', progress: 0 } ]; + tests.forEach(function(test) { + var anim = createDiv(t).animate(null, { delay: 1, fill: test.fill }); + assert_equals(anim.effect.getComputedTiming().progress, test.progress, + 'Progress in before phase when using \'' + test.fill + + '\' fill'); + }); +}, 'Active time in before phase'); + +test(function(t) { + var anim = createDiv(t).animate(null, 1000); + anim.currentTime = 500; + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and no start delay is the local time'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, delay: 500 }); + anim.currentTime = 1000; + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and positive start delay is the local time' + + ' minus the start delay'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, delay: -500 }); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and negative start delay is the local time' + + ' minus the start delay'); + +test(function(t) { + var anim = createDiv(t).animate(null); + assert_equals(anim.effect.getComputedTiming().progress, null); +}, 'Active time in after phase with no fill is unresolved'); + +test(function(t) { + var anim = createDiv(t).animate(null, { fill: 'backwards' }); + assert_equals(anim.effect.getComputedTiming().progress, null); +}, 'Active time in after phase with backwards-only fill is unresolved'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, // Should have no effect + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with forwards fill is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 0, + iterations: Infinity, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, Infinity); + assert_equals(anim.effect.getComputedTiming().progress, 1); +}, 'Active time in after phase with forwards fill, zero-duration, and ' + + ' infinite iteration count is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: 4000, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with forwards fill and positive end delay' + + ' is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -800, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 1); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' is the active duration + end delay'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -2500, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 0); + assert_equals(anim.effect.getComputedTiming().progress, 0); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' greater in magnitude than the active duration is zero'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -4000, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 0); + assert_equals(anim.effect.getComputedTiming().progress, 0); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' greater in magnitude than the sum of the active duration and start delay' + + ' is zero'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + fill: 'both' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with \'both\' fill is the active duration'); + +test(function(t) { + // Create an effect with a non-zero duration so we ensure we're not just + // testing the after-phase behavior. + var effect = new KeyframeEffect(null, null, 1); + assert_equals(effect.getComputedTiming().progress, null); +}, 'Active time when the local time is unresolved, is unresolved'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animation-effects/current-iteration.html b/testing/web-platform/tests/web-animations/timing-model/animation-effects/current-iteration.html new file mode 100644 index 000000000..d24908628 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/current-iteration.html @@ -0,0 +1,584 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Current iteration tests</title> +<link rel="help" href="https://w3c.github.io/web-animations/#current-iteration"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +function runTests(tests, description) { + tests.forEach(function(currentTest) { + var testParams = ''; + for (var attr in currentTest.input) { + testParams += ' ' + attr + ':' + currentTest.input[attr]; + } + test(function(t) { + var div = createDiv(t); + var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input); + assert_equals(anim.effect.getComputedTiming().currentIteration, + currentTest.before); + anim.currentTime = currentTest.input.delay || 0; + assert_equals(anim.effect.getComputedTiming().currentIteration, + currentTest.active); + if (typeof currentTest.after !== 'undefined') { + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, + currentTest.after); + } + }, description + ':' + testParams); + }); +} + +async_test(function(t) { + var div = createDiv(t); + var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 }); + assert_equals(anim.effect.getComputedTiming().currentIteration, null); + anim.finished.then(t.step_func(function() { + assert_equals(anim.effect.getComputedTiming().currentIteration, null); + t.done(); + })); +}, 'Test currentIteration during before and after phase when fill is none'); + + +// -------------------------------------------------------------------- +// +// Zero iteration duration tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 0, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 2, + active: 2, + after: 2 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 2, + active: 2, + after: 2 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 2, + active: 2, + after: 2 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 3, + active: 3, + after: 3 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 3, + active: 3, + after: 3 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 3, + active: 3, + after: 3 + } +], 'Test zero iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is an integer +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 3, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 2, + after: 2 + }, + + { + input: { iterations: 3, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 2 + }, + + { + input: { iterations: 3, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 2, + active: 5, + after: 5 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 2, + active: 2, + after: 5 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 2, + active: 2 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 3, + active: 5, + after: 5 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 3, + active: 3, + after: 5 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 3, + active: 3 + } +], 'Test integer iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is a fraction +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 3.5, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 3, + after: 3 + }, + + { + input: { iterations: 3.5, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 3 + }, + + { + input: { iterations: 3.5, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 2, + active: 5, + after: 5 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 2, + active: 2, + after: 5 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 2, + active: 2 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 3, + active: 6, + after: 6 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 3, + active: 3, + after: 6 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 3, + active: 3 + } +], 'Test fractional iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is Infinity +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: Infinity, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: Infinity, + after: Infinity + }, + + { + input: { iterations: Infinity, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: Infinity, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 2, + active: Infinity, + after: Infinity + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 2, + active: 2 + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 2, + active: 2 + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 3, + active: Infinity, + after: Infinity + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 3, + active: 3 + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 3, + active: 3 + } +], 'Test infinity iterations'); + + +// -------------------------------------------------------------------- +// +// End delay tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -200 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 2, + active: 2, + after: 2 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 2, + active: 2, + after: 2 + }, +], 'Test end delay'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animation-effects/phases-and-states.html b/testing/web-platform/tests/web-animations/timing-model/animation-effects/phases-and-states.html new file mode 100644 index 000000000..5dc32066f --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/phases-and-states.html @@ -0,0 +1,191 @@ +<!doctype html> +<meta charset=utf-8> +<title>Tests for phases and states</title> +<link rel="help" href="https://w3c.github.io/web-animations/#animation-effect-phases-and-states"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +// -------------------------------------------------------------------- +// +// Phases +// +// -------------------------------------------------------------------- + +function assert_phase_at_time(animation, phase, currentTime) { + animation.currentTime = currentTime; + + if (phase === 'active') { + // If the fill mode is 'none', then progress will only be non-null if we + // are in the active phase. + animation.effect.timing.fill = 'none'; + assert_not_equals(animation.effect.getComputedTiming().progress, null, + 'Animation effect is in active phase when current time' + + ' is ' + currentTime + 'ms'); + } else { + // The easiest way to distinguish between the 'before' phase and the 'after' + // phase is to toggle the fill mode. For example, if the progress is null + // will the fill node is 'none' but non-null when the fill mode is + // 'backwards' then we are in the before phase. + animation.effect.timing.fill = 'none'; + assert_equals(animation.effect.getComputedTiming().progress, null, + 'Animation effect is in ' + phase + ' phase when current time' + + ' is ' + currentTime + 'ms' + + ' (progress is null with \'none\' fill mode)'); + + animation.effect.timing.fill = phase === 'before' + ? 'backwards' + : 'forwards'; + assert_not_equals(animation.effect.getComputedTiming().progress, null, + 'Animation effect is in ' + phase + ' phase when current' + + ' time is ' + currentTime + 'ms' + + ' (progress is non-null with appropriate fill mode)'); + } +} + +test(function(t) { + var animation = createDiv(t).animate(null, 1); + + [ { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 1, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for a simple animation effect'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, delay: 1 }); + + [ { currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a positive start delay'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, delay: -1 }); + + [ { currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative start delay'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, endDelay: 1 }); + + [ { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 1, phase: 'after' }, + { currentTime: 2, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a positive end delay'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 2, endDelay: -1 }); + + [ { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'active' }, + { currentTime: 0.9, phase: 'active' }, + { currentTime: 1, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative end delay lesser' + + ' in magnitude than the active duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, endDelay: -1 }); + + [ { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' }, + { currentTime: 1, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative end delay equal' + + ' in magnitude to the active duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, endDelay: -2 }); + + [ { currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative end delay' + + ' greater in magnitude than the active duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 2, + delay: 1, + endDelay: -1 }); + + [ { currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a positive start delay' + + ' and a negative end delay lesser in magnitude than the active duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, + delay: -1, + endDelay: -1 }); + + [ { currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative start delay' + + ' and a negative end delay equal in magnitude to the active duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, { duration: 1, + delay: -1, + endDelay: -2 }); + + [ { currentTime: -3, phase: 'before' }, + { currentTime: -2, phase: 'before' }, + { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for an animation effect with a negative start delay' + + ' and a negative end delay equal greater in magnitude than the active' + + ' duration'); + +test(function(t) { + var animation = createDiv(t).animate(null, 1); + animation.playbackRate = -1; + + [ { currentTime: -1, phase: 'before' }, + { currentTime: 0, phase: 'before' }, + { currentTime: 1, phase: 'active' }, + { currentTime: 2, phase: 'after' } ] + .forEach(function(test) { + assert_phase_at_time(animation, test.phase, test.currentTime); + }); +}, 'Phase calculation for a simple animation effect with negative playback' + + ' rate'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html b/testing/web-platform/tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html new file mode 100644 index 000000000..f6a3a51bd --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html @@ -0,0 +1,575 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Simple iteration progress tests</title> +<link rel="help" + href="https://w3c.github.io/web-animations/#simple-iteration-progress"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +function runTests(tests, description) { + tests.forEach(function(currentTest) { + var testParams = ''; + for (var attr in currentTest.input) { + testParams += ' ' + attr + ':' + currentTest.input[attr]; + } + test(function(t) { + var div = createDiv(t); + var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input); + assert_equals(anim.effect.getComputedTiming().progress, + currentTest.before); + anim.currentTime = currentTest.input.delay || 0; + assert_equals(anim.effect.getComputedTiming().progress, + currentTest.active); + if (typeof currentTest.after !== 'undefined') { + anim.finish(); + assert_equals(anim.effect.getComputedTiming().progress, + currentTest.after); + } + }, description + ':' + testParams); + }); +} + + +// -------------------------------------------------------------------- +// +// Zero iteration duration tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 0, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 0, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 0, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0 + } +], 'Test zero iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is an integer +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 3, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 1, + after: 1 + }, + + { + input: { iterations: 3, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterations: 3, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 3, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 1, + after: 1 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterations: 3, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + } +], 'Test integer iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is a fraction +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: 3.5, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 3.5, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { iterations: 3.5, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 1, + after: 1 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 1 + }, + + { + input: { iterations: 3.5, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { iterations: 3.5, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + } +], 'Test fractional iterations'); + + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is Infinity +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { iterations: Infinity, + iterationStart: 0, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 1, + after: 1 + }, + + { + input: { iterations: Infinity, + iterationStart: 0, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: Infinity, + iterationStart: 0, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5 + }, + + { + input: { iterations: Infinity, + iterationStart: 2.5, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0.5, + active: 0.5 + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: 0, + delay: 1, + fill: 'both' }, + before: 0, + active: 1, + after: 1 + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: 100, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + }, + + { + input: { iterations: Infinity, + iterationStart: 3, + duration: Infinity, + delay: 1, + fill: 'both' }, + before: 0, + active: 0 + } +], 'Test infinity iterations'); + + +// -------------------------------------------------------------------- +// +// End delay tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -200 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0.5, + active: 0.5, + after: 1 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, +], 'Test end delay'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/current-time.html b/testing/web-platform/tests/web-animations/timing-model/animations/current-time.html new file mode 100644 index 000000000..efc7ba78b --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/current-time.html @@ -0,0 +1,65 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Tests for current time</title> +<link rel="help" href="https://w3c.github.io/web-animations/#current-time"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + animation.play(); + assert_equals(animation.currentTime, 0, + 'Current time returns the hold time set when entering the play-pending ' + + 'state'); +}, 'The current time returns the hold time when set'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + + return animation.ready.then(function() { + assert_equals(animation.currentTime, null); + }); +}, 'The current time is unresolved when there is no associated timeline ' + + '(and no hold time is set)'); + +// FIXME: Test that the current time is unresolved when we have an inactive +// timeline if we find a way of creating an inactive timeline! + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + animation.startTime = null; + assert_equals(animation.currentTime, null); +}, 'The current time is unresolved when the start time is unresolved ' + + '(and no hold time is set)'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + animation.playbackRate = 2; + animation.startTime = document.timeline.currentTime - 25 * MS_PER_SEC; + + var timelineTime = document.timeline.currentTime; + var startTime = animation.startTime; + var playbackRate = animation.playbackRate; + assert_times_equal(animation.currentTime, + (timelineTime - startTime) * playbackRate, + 'Animation has a unresolved start time'); +}, 'The current time is calculated from the timeline time, start time and ' + + 'playback rate'); +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html new file mode 100644 index 000000000..8b74c92a4 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html @@ -0,0 +1,207 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Setting the start time tests</title> +<link rel="help" href="https://w3c.github.io/web-animations/#set-the-animation-start-time"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function(t) +{ + // It should only be possible to set *either* the start time or the current + // time for an animation that does not have an active timeline. + + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + + assert_equals(animation.currentTime, null, 'Intial current time'); + assert_equals(animation.startTime, null, 'Intial start time'); + + animation.currentTime = 1000; + assert_equals(animation.currentTime, 1000, + 'Setting the current time succeeds'); + assert_equals(animation.startTime, null, + 'Start time remains null after setting current time'); + + animation.startTime = 1000; + assert_equals(animation.startTime, 1000, + 'Setting the start time succeeds'); + assert_equals(animation.currentTime, null, + 'Setting the start time clears the current time'); + + animation.startTime = null; + assert_equals(animation.startTime, null, + 'Setting the start time to an unresolved time succeeds'); + assert_equals(animation.currentTime, null, 'The current time is unaffected'); + +}, 'Setting the start time of an animation without an active timeline'); + +test(function(t) +{ + // Setting an unresolved start time on an animation without an active + // timeline should not clear the current time. + + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + + assert_equals(animation.currentTime, null, 'Intial current time'); + assert_equals(animation.startTime, null, 'Intial start time'); + + animation.currentTime = 1000; + assert_equals(animation.currentTime, 1000, + 'Setting the current time succeeds'); + assert_equals(animation.startTime, null, + 'Start time remains null after setting current time'); + + animation.startTime = null; + assert_equals(animation.startTime, null, 'Start time remains unresolved'); + assert_equals(animation.currentTime, 1000, 'Current time is unaffected'); + +}, 'Setting an unresolved start time an animation without an active timeline' + + ' does not clear the current time'); + +test(function(t) +{ + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + // So long as a hold time is set, querying the current time will return + // the hold time. + + // Since the start time is unresolved at this point, setting the current time + // will set the hold time + animation.currentTime = 1000; + assert_equals(animation.currentTime, 1000, + 'The current time is calculated from the hold time'); + + // If we set the start time, however, we should clear the hold time. + animation.startTime = document.timeline.currentTime - 2000; + assert_times_equal(animation.currentTime, 2000, + 'The current time is calculated from the start time,' + + ' not the hold time'); + + // Sanity check + assert_equals(animation.playState, 'running', + 'Animation reports it is running after setting a resolved' + + ' start time'); +}, 'Setting the start time clears the hold time'); + +test(function(t) +{ + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + // Set up a running animation (i.e. both start time and current time + // are resolved). + animation.startTime = document.timeline.currentTime - 1000; + assert_equals(animation.playState, 'running'); + assert_times_equal(animation.currentTime, 1000, + 'Current time is resolved for a running animation') + + // Clear start time + animation.startTime = null; + assert_times_equal(animation.currentTime, 1000, + 'Hold time is set after start time is made unresolved'); + assert_equals(animation.playState, 'paused', + 'Animation reports it is paused after setting an unresolved' + + ' start time'); +}, 'Setting an unresolved start time sets the hold time'); + +promise_test(function(t) +{ + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + var readyPromiseCallbackCalled = false; + animation.ready.then(function() { readyPromiseCallbackCalled = true; } ); + + // Put the animation in the play-pending state + animation.play(); + + // Sanity check + assert_equals(animation.playState, 'pending', + 'Animation is in play-pending state'); + + // Setting the start time should resolve the 'ready' promise, i.e. + // it should schedule a microtask to run the promise callbacks. + animation.startTime = document.timeline.currentTime; + assert_false(readyPromiseCallbackCalled, + 'Ready promise callback is not called synchronously'); + + // If we schedule another microtask then it should run immediately after + // the ready promise resolution microtask. + return Promise.resolve().then(function() { + assert_true(readyPromiseCallbackCalled, + 'Ready promise callback called after setting startTime'); + }); +}, 'Setting the start time resolves a pending ready promise'); + +promise_test(function(t) +{ + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + var readyPromiseCallbackCalled = false; + animation.ready.then(function() { readyPromiseCallbackCalled = true; } ); + + // Put the animation in the pause-pending state + animation.startTime = document.timeline.currentTime; + animation.pause(); + + // Sanity check + assert_equals(animation.playState, 'pending', + 'Animation is in pause-pending state'); + + // Setting the start time should resolve the 'ready' promise although + // the resolution callbacks when be run in a separate microtask. + animation.startTime = null; + assert_false(readyPromiseCallbackCalled, + 'Ready promise callback is not called synchronously'); + + return Promise.resolve().then(function() { + assert_true(readyPromiseCallbackCalled, + 'Ready promise callback called after setting startTime'); + }); +}, 'Setting the start time resolves a pending pause task'); + +promise_test(function(t) +{ + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + + // Set start time such that the current time is past the end time + animation.startTime = document.timeline.currentTime + - 110 * MS_PER_SEC; + assert_equals(animation.playState, 'finished', + 'Seeked to finished state using the startTime'); + + // If the 'did seek' flag is true, the current time should be greater than + // the effect end. + assert_greater_than(animation.currentTime, + animation.effect.getComputedTiming().endTime, + 'Setting the start time updated the finished state with' + + ' the \'did seek\' flag set to true'); + + // Furthermore, that time should persist if we have correctly updated + // the hold time + var finishedCurrentTime = animation.currentTime; + return waitForAnimationFrames(1).then(function() { + assert_equals(animation.currentTime, finishedCurrentTime, + 'Current time does not change after seeking past the effect' + + ' end time by setting the current time'); + }); +}, 'Setting the start time updates the finished state'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html new file mode 100644 index 000000000..4c51f0141 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Setting the target effect tests</title> +<link rel='help' href='https://w3c.github.io/web-animations/#setting-the-target-effect'> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script src='../../testcommon.js'></script> +<body> +<div id='log'></div> +<script> +'use strict'; + +promise_test(function(t) { + var anim = createDiv(t).animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + assert_equals(anim.playState, 'pending'); + + var retPromise = anim.ready.then(function() { + assert_unreached('ready promise is fulfilled'); + }).catch(function(err) { + assert_equals(err.name, 'AbortError', + 'ready promise is rejected with AbortError'); + }); + + anim.effect = null; + assert_equals(anim.playState, 'paused'); + + return retPromise; +}, 'If new effect is null and old effect is not null, we reset the pending ' + + 'tasks and ready promise is rejected'); + +promise_test(function(t) { + var anim = new Animation(); + anim.pause(); + assert_equals(anim.playState, 'pending'); + + anim.effect = new KeyframeEffectReadOnly(createDiv(t), + { marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + assert_equals(anim.playState, 'pending'); + + return anim.ready.then(function() { + assert_equals(anim.playState, 'paused'); + }); +}, 'If animation has a pending pause task, reschedule that task to run ' + + 'as soon as animation is ready.'); + +promise_test(function(t) { + var anim = new Animation(); + anim.play(); + assert_equals(anim.playState, 'pending'); + + anim.effect = new KeyframeEffectReadOnly(createDiv(t), + { marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + assert_equals(anim.playState, 'pending'); + + return anim.ready.then(function() { + assert_equals(anim.playState, 'running'); + }); +}, 'If animation has a pending play task, reschedule that task to run ' + + 'as soon as animation is ready to play new effect.'); + +promise_test(function(t) { + var animA = createDiv(t).animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + var animB = new Animation(); + + return animA.ready.then(function() { + animB.effect = animA.effect; + assert_equals(animA.effect, null); + assert_equals(animA.playState, 'finished'); + }); +}, 'When setting the effect of an animation to the effect of an existing ' + + 'animation, the existing animation\'s target effect should be set to null.'); + +test(function(t) { + var animA = createDiv(t).animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + var animB = new Animation(); + var effect = animA.effect; + animA.currentTime = 50 * MS_PER_SEC; + animB.currentTime = 20 * MS_PER_SEC; + assert_equals(effect.getComputedTiming().progress, 0.5, + 'Original timing comes from first animation'); + animB.effect = effect; + assert_equals(effect.getComputedTiming().progress, 0.2, + 'After setting the effect on a different animation, ' + + 'it uses the new animation\'s timing'); +}, 'After setting the target effect of animation to the target effect of an ' + + 'existing animation, the target effect\'s timing is updated to reflect ' + + 'the current time of the new animation.'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html new file mode 100644 index 000000000..c540fe2ca --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html @@ -0,0 +1,276 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Setting the timeline tests</title> +<link rel="help" href="https://w3c.github.io/web-animations/#setting-the-timeline"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +// --------------------------------------------------------------------- +// +// Tests from no timeline to timeline +// +// --------------------------------------------------------------------- + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.currentTime = 50 * MS_PER_SEC; + assert_equals(animation.playState, 'paused'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'paused'); + assert_times_equal(animation.currentTime, 50 * MS_PER_SEC); +}, 'After setting timeline on paused animation it is still paused'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.currentTime = 200 * MS_PER_SEC; + assert_equals(animation.playState, 'paused'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'paused'); + assert_times_equal(animation.currentTime, 200 * MS_PER_SEC); +}, 'After setting timeline on animation paused outside active interval' + + ' it is still paused'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + assert_equals(animation.playState, 'idle'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'idle'); +}, 'After setting timeline on an idle animation without a start time' + + ' it is still idle'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.startTime = document.timeline.currentTime; + assert_equals(animation.playState, 'idle'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'running'); +}, 'After setting timeline on an idle animation with a start time' + + ' it is running'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.startTime = document.timeline.currentTime - 200 * MS_PER_SEC; + assert_equals(animation.playState, 'idle'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'finished'); +}, 'After setting timeline on an idle animation with a sufficiently ancient' + + ' start time it is finished'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.play(); + assert_equals(animation.playState, 'pending'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'pending'); +}, 'After setting timeline on a play-pending animation it is still pending'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.play(); + assert_equals(animation.playState, 'pending'); + + animation.timeline = document.timeline; + + return animation.ready.then(function() { + assert_equals(animation.playState, 'running'); + }); +}, 'After setting timeline on a play-pending animation it begins playing' + + ' after pending'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.startTime = document.timeline.currentTime; + animation.pause(); + animation.timeline = null; + assert_equals(animation.playState, 'pending'); + + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'pending'); +}, 'After setting timeline on a pause-pending animation it is still pending'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + null); + animation.startTime = document.timeline.currentTime; + animation.pause(); + animation.timeline = null; + assert_equals(animation.playState, 'pending'); + + animation.timeline = document.timeline; + + return animation.ready.then(function() { + assert_equals(animation.playState, 'paused'); + }); +}, 'After setting timeline on a pause-pending animation it becomes paused' + + ' after pending'); + +// --------------------------------------------------------------------- +// +// Tests from timeline to no timeline +// +// --------------------------------------------------------------------- + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + animation.currentTime = 50 * MS_PER_SEC; + assert_equals(animation.playState, 'paused'); + + animation.timeline = null; + + assert_equals(animation.playState, 'paused'); + assert_times_equal(animation.currentTime, 50 * MS_PER_SEC); +}, 'After clearing timeline on paused animation it is still paused'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + var initialStartTime = document.timeline.currentTime - 200 * MS_PER_SEC; + animation.startTime = initialStartTime; + assert_equals(animation.playState, 'finished'); + + animation.timeline = null; + + assert_equals(animation.playState, 'idle'); + assert_times_equal(animation.startTime, initialStartTime); +}, 'After clearing timeline on finished animation it is idle'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; + animation.startTime = initialStartTime; + assert_equals(animation.playState, 'running'); + + animation.timeline = null; + + assert_equals(animation.playState, 'idle'); + assert_times_equal(animation.startTime, initialStartTime); +}, 'After clearing timeline on running animation it is idle'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + assert_equals(animation.playState, 'idle'); + + animation.timeline = null; + + assert_equals(animation.playState, 'idle'); + assert_equals(animation.startTime, null); +}, 'After clearing timeline on idle animation it is still idle'); + +test(function(t) { + var animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + assert_equals(animation.playState, 'pending'); + + animation.timeline = null; + + assert_equals(animation.playState, 'pending'); +}, 'After clearing timeline on play-pending animation it is still pending'); + +promise_test(function(t) { + var animation = createDiv(t).animate(null, 100 * MS_PER_SEC); + assert_equals(animation.playState, 'pending'); + + animation.timeline = null; + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'pending'); + return animation.ready.then(function() { + assert_equals(animation.playState, 'running'); + }); +}, 'After clearing and re-setting timeline on play-pending animation it' + + ' begins to play'); + +test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + animation.startTime = document.timeline.currentTime; + animation.pause(); + assert_equals(animation.playState, 'pending'); + + animation.timeline = null; + + assert_equals(animation.playState, 'pending'); +}, 'After clearing timeline on a pause-pending animation it is still pending'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + animation.startTime = document.timeline.currentTime; + animation.pause(); + assert_equals(animation.playState, 'pending'); + + animation.timeline = null; + animation.timeline = document.timeline; + + assert_equals(animation.playState, 'pending'); + return animation.ready.then(function() { + assert_equals(animation.playState, 'paused'); + }); +}, 'After clearing and re-setting timeline on a pause-pending animation it' + + ' becomes paused'); + +promise_test(function(t) { + var animation = + new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), + document.timeline); + var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC; + animation.startTime = initialStartTime; + animation.pause(); + animation.play(); + + animation.timeline = null; + animation.timeline = document.timeline; + assert_equals(animation.playState, 'pending'); + + return animation.ready.then(function() { + assert_equals(animation.playState, 'running'); + assert_times_equal(animation.startTime, initialStartTime); + }); +}, 'After clearing and re-setting timeline on an animation in the middle of' + + ' an aborted pause, it continues playing using the same start time'); + +</script> +</body> diff --git a/testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html b/testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html new file mode 100644 index 000000000..0b77443f2 --- /dev/null +++ b/testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html @@ -0,0 +1,331 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Tests for updating the finished state of an animation</title> +<link rel="help" href="https://w3c.github.io/web-animations/#updating-the-finished-state"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +// +// NOTE TO THE POOR PERSON WHO HAS TO MERGE THIS WITH THE TEST OF THE SAME +// NAME FROM BLINK +// +// There is a pull request from Blink at: +// +// https://github.com/w3c/web-platform-tests/pull/3328 +// +// which this file will surely conflict with. +// +// However, those tests cover a different part of the same algorithm. They +// are mostly concerned with testing events and promises rather than the +// timing part of the algorithm. +// +// The tests below cover the first part of the algorithm. So, please keep both +// sets of tests and delete this comment. Preferably put the tests in this +// file first. +// +// Thank you! +// + + +// CASE 1: playback rate > 0 and current time >= target effect end +// (Also the start time is resolved and there is pending task) + +// Did seek = false +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + + // Here and in the following tests we wait until ready resolves as + // otherwise we don't have a resolved start time. We test the case + // where the start time is unresolved in a subsequent test. + return anim.ready.then(function() { + // Seek to 1ms before the target end and then wait 1ms + anim.currentTime = 100 * MS_PER_SEC - 1; + return waitForAnimationFramesWithDelay(1); + }).then(function() { + assert_equals(anim.currentTime, 100 * MS_PER_SEC, + 'Hold time is set to target end clamping current time'); + }); +}, 'Updating the finished state when playing past end'); + +// Did seek = true +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + return anim.ready.then(function() { + anim.currentTime = 200 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, 200 * MS_PER_SEC, + 'Hold time is set so current time should NOT change'); + }); +}, 'Updating the finished state when seeking past end'); + +// Test current time == target end +// +// We can't really write a test for current time == target end with +// did seek = false since that would imply setting up an animation where +// the next animation frame time happens to exactly align with the target end. +// +// Fortunately, we don't need to test that case since even if the implementation +// fails to set the hold time on such a tick, it should be mostly unobservable +// (on the subsequent tick the hold time will be set to the same value anyway). + +// Did seek = true +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + return anim.ready.then(function() { + anim.currentTime = 100 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, 100 * MS_PER_SEC, + 'Hold time is set so current time should NOT change'); + }); +}, 'Updating the finished state when seeking exactly to end'); + + +// CASE 2: playback rate < 0 and current time <= 0 +// (Also the start time is resolved and there is pending task) + +// Did seek = false +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = -1; + anim.play(); // Make sure animation is not initially finished + return anim.ready.then(function() { + // Seek to 1ms before 0 and then wait 1ms + anim.currentTime = 1; + return waitForAnimationFramesWithDelay(1); + }).then(function() { + assert_equals(anim.currentTime, 0 * MS_PER_SEC, + 'Hold time is set to zero clamping current time'); + }); +}, 'Updating the finished state when playing in reverse past zero'); + +// Did seek = true +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = -1; + anim.play(); + return anim.ready.then(function() { + anim.currentTime = -100 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, -100 * MS_PER_SEC, + 'Hold time is set so current time should NOT change'); + }); +}, 'Updating the finished state when seeking a reversed animation past zero'); + +// As before, it's difficult to test current time == 0 for did seek = false but +// it doesn't really matter. + +// Did seek = true +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = -1; + anim.play(); + return anim.ready.then(function() { + anim.currentTime = 0; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, 0 * MS_PER_SEC, + 'Hold time is set so current time should NOT change'); + }); +}, 'Updating the finished state when seeking a reversed animation exactly' + + ' to zero'); + +// CASE 3: playback rate > 0 and current time < target end OR +// playback rate < 0 and current time > 0 +// (Also the start time is resolved and there is pending task) + +// Did seek = false; playback rate > 0 +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + + // We want to test that the hold time is cleared so first we need to + // put the animation in a state where the hold time is set. + anim.finish(); + return anim.ready.then(function() { + assert_equals(anim.currentTime, 100 * MS_PER_SEC, + 'Hold time is initially set'); + // Then extend the duration so that the hold time is cleared and on + // the next tick the current time will increase. + anim.effect.timing.duration *= 2; + return waitForAnimationFrames(1); + }).then(function() { + assert_greater_than(anim.currentTime, 100 * MS_PER_SEC, + 'Hold time is not set so current time should increase'); + }); +}, 'Updating the finished state when playing before end'); + +// Did seek = true; playback rate > 0 +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.finish(); + return anim.ready.then(function() { + anim.currentTime = 50 * MS_PER_SEC; + // When did seek = true, updating the finished state: (i) updates + // the animation's start time and (ii) clears the hold time. + // We can test both by checking that the currentTime is initially + // updated and then increases. + assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated'); + return waitForAnimationFrames(1); + }).then(function() { + assert_greater_than(anim.currentTime, 50 * MS_PER_SEC, + 'Hold time is not set so current time should increase'); + }); +}, 'Updating the finished state when seeking before end'); + +// Did seek = false; playback rate < 0 +// +// Unfortunately it is not possible to test this case. We need to have +// a hold time set, a resolved start time, and then perform some +// operation that updates the finished state with did seek set to true. +// +// However, the only situation where this could arrive is when we +// replace the timeline and that procedure is likely to change. For all +// other cases we either have an unresolved start time (e.g. when +// paused), we don't have a set hold time (e.g. regular playback), or +// the current time is zero (and anything that gets us out of that state +// will set did seek = true). + +// Did seek = true; playback rate < 0 +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = -1; + return anim.ready.then(function() { + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated'); + return waitForAnimationFrames(1); + }).then(function() { + assert_less_than(anim.currentTime, 50 * MS_PER_SEC, + 'Hold time is not set so current time should decrease'); + }); +}, 'Updating the finished state when seeking a reversed animation before end'); + +// CASE 4: playback rate == 0 + +// current time < 0 +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = 0; + return anim.ready.then(function() { + anim.currentTime = -100 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, -100 * MS_PER_SEC, + 'Hold time should not be cleared so current time should' + + ' NOT change'); + }); +}, 'Updating the finished state when playback rate is zero and the' + + ' current time is less than zero'); + +// current time < target end +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = 0; + return anim.ready.then(function() { + anim.currentTime = 50 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, 50 * MS_PER_SEC, + 'Hold time should not be cleared so current time should' + + ' NOT change'); + }); +}, 'Updating the finished state when playback rate is zero and the' + + ' current time is less than end'); + +// current time > target end +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.playbackRate = 0; + return anim.ready.then(function() { + anim.currentTime = 200 * MS_PER_SEC; + return waitForAnimationFrames(1); + }).then(function() { + assert_equals(anim.currentTime, 200 * MS_PER_SEC, + 'Hold time should not be cleared so current time should' + + ' NOT change'); + }); +}, 'Updating the finished state when playback rate is zero and the' + + ' current time is greater than end'); + +// CASE 5: current time unresolved + +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.cancel(); + // Trigger a change that will cause the "update the finished state" + // procedure to run. + anim.effect.timing.duration = 200 * MS_PER_SEC; + assert_equals(anim.currentTime, null, + 'The animation hold time / start time should not be updated'); + // The "update the finished state" procedure is supposed to run after any + // change to timing, but just in case an implementation defers that, let's + // wait a frame and check that the hold time / start time has still not been + // updated. + return waitForAnimationFrames(1).then(function() { + assert_equals(anim.currentTime, null, + 'The animation hold time / start time should not be updated'); + }); +}, 'Updating the finished state when current time is unresolved'); + +// CASE 6: has a pending task + +test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.cancel(); + anim.currentTime = 75 * MS_PER_SEC; + anim.play(); + // We now have a pending task and a resolved current time. + // + // In the next step we will adjust the timing so that the current time + // is greater than the target end. At this point the "update the finished + // state" procedure should run and if we fail to check for a pending task + // we will set the hold time to the target end, i.e. 50ms. + anim.effect.timing.duration = 50 * MS_PER_SEC; + assert_equals(anim.currentTime, 75 * MS_PER_SEC, + 'Hold time should not be updated'); +}, 'Updating the finished state when there is a pending task'); + +// CASE 7: start time unresolved + +// Did seek = false +promise_test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.cancel(); + // Make it so that only the start time is unresolved (to avoid overlapping + // with the test case where current time is unresolved) + anim.currentTime = 150 * MS_PER_SEC; + // Trigger a change that will cause the "update the finished state" + // procedure to run (did seek = false). + anim.effect.timing.duration = 200 * MS_PER_SEC; + return waitForAnimationFrames(1).then(function() { + assert_equals(anim.currentTime, 150 * MS_PER_SEC, + 'The animation hold time should not be updated'); + assert_equals(anim.startTime, null, + 'The animation start time should not be updated'); + }); +}, 'Updating the finished state when start time is unresolved and' + + ' did seek = false'); + +// Did seek = true +test(function(t) { + var anim = createDiv(t).animate(null, 100 * MS_PER_SEC); + anim.cancel(); + anim.currentTime = 150 * MS_PER_SEC; + // Trigger a change that will cause the "update the finished state" + // procedure to run. + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(anim.currentTime, 50 * MS_PER_SEC, + 'The animation hold time should not be updated'); + assert_equals(anim.startTime, null, + 'The animation start time should not be updated'); +}, 'Updating the finished state when start time is unresolved and' + + ' did seek = true'); + +</script> +</body> |