| <!doctype html> |
| <meta charset=utf-8> |
| <title>Scroll based animation: AnimationEffect.updateTiming</title> |
| <!-- Adapted to progressed based scroll animations from "wpt\web-animations\interfaces\AnimationEffect\updateTiming.html" --> |
| <link rel="help" href="https://drafts.csswg.org/web-animations-1/#dom-animationeffect-updatetiming"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/web-animations/testcommon.js"></script> |
| <script src="testcommon.js"></script> |
| <script src="/web-animations/resources/easing-tests.js"></script> |
| <script src="/web-animations/resources/timing-tests.js"></script> |
| <style> |
| .scroller { |
| overflow: auto; |
| height: 100px; |
| width: 100px; |
| will-change: transform; |
| } |
| .contents { |
| height: 1000px; |
| width: 100%; |
| } |
| </style> |
| <body> |
| <div id="log"></div> |
| <script> |
| 'use strict'; |
| |
| // ------------------------------ |
| // delay |
| // ------------------------------ |
| |
| promise_test(async t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, {duration: 1000, delay: 200}) |
| anim.play(); |
| |
| assert_equals(anim.effect.getTiming().delay, 200, 'initial delay 200'); |
| assert_equals(anim.effect.getComputedTiming().delay, 200, |
| 'getComputedTiming() initially delay 200'); |
| |
| anim.effect.updateTiming({ delay: 100 }); |
| assert_equals(anim.effect.getTiming().delay, 100, 'set delay 100'); |
| assert_equals(anim.effect.getComputedTiming().delay, 100, |
| 'getComputedTiming() after set delay 100'); |
| }, 'Allows setting the delay to a positive number'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100, delay: -100}) |
| anim.play(); |
| anim.effect.updateTiming({ delay: -100 }); |
| assert_equals(anim.effect.getTiming().delay, -100, 'set delay -100'); |
| assert_equals(anim.effect.getComputedTiming().delay, -100, |
| 'getComputedTiming() after set delay -100'); |
| assert_percents_equal(anim.effect.getComputedTiming().endTime, 0, |
| 'getComputedTiming().endTime after set delay -100'); |
| }, 'Allows setting the delay to a negative number'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100}) |
| anim.play(); |
| anim.effect.updateTiming({ delay: 100 }); |
| assert_equals(anim.effect.getComputedTiming().progress, null); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, null); |
| }, 'Allows setting the delay of an animation in progress: positive delay that' |
| + ' causes the animation to be no longer in-effect'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 }) |
| anim.play(); |
| anim.effect.updateTiming({ delay: -50 }); |
| assert_equals(anim.effect.getComputedTiming().progress, 0.5); |
| }, 'Allows setting the delay of an animation in progress: negative delay that' |
| + ' seeks into the active interval'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 }) |
| anim.play(); |
| anim.effect.updateTiming({ delay: -100 }); |
| assert_equals(anim.effect.getComputedTiming().progress, 1); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0); |
| }, 'Allows setting the delay of an animation in progress: large negative delay' |
| + ' that causes the animation to be finished'); |
| |
| for (const invalid of gBadDelayValues) { |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t) |
| anim.play(); |
| assert_throws_js(TypeError, () => { |
| anim.effect.updateTiming({ delay: invalid }); |
| }); |
| }, `Throws when setting invalid delay value: ${invalid}`); |
| } |
| |
| |
| // ------------------------------ |
| // endDelay |
| // ------------------------------ |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| anim.effect.updateTiming({ endDelay: 123.45 }); |
| assert_time_equals_literal(anim.effect.getTiming().endDelay, 123.45, |
| 'set endDelay 123.45'); |
| assert_time_equals_literal(anim.effect.getComputedTiming().endDelay, 123.45, |
| 'getComputedTiming() after set endDelay 123.45'); |
| }, 'Allows setting the endDelay to a positive number'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| anim.effect.updateTiming({ endDelay: -1000 }); |
| assert_equals(anim.effect.getTiming().endDelay, -1000, 'set endDelay -1000'); |
| assert_equals(anim.effect.getComputedTiming().endDelay, -1000, |
| 'getComputedTiming() after set endDelay -1000'); |
| }, 'Allows setting the endDelay to a negative number'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| assert_throws_js(TypeError, () => { |
| anim.effect.updateTiming({ endDelay: Infinity }); |
| }); |
| }, 'Throws when setting the endDelay to infinity'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| assert_throws_js(TypeError, () => { |
| anim.effect.updateTiming({ endDelay: -Infinity }); |
| }); |
| }, 'Throws when setting the endDelay to negative infinity'); |
| |
| |
| // ------------------------------ |
| // fill |
| // ------------------------------ |
| |
| for (const fill of ['none', 'forwards', 'backwards', 'both']) { |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100 }) |
| anim.play(); |
| anim.effect.updateTiming({ fill }); |
| assert_equals(anim.effect.getTiming().fill, fill, 'set fill ' + fill); |
| assert_equals(anim.effect.getComputedTiming().fill, fill, |
| 'getComputedTiming() after set fill ' + fill); |
| }, `Allows setting the fill to '${fill}'`); |
| } |
| |
| |
| // ------------------------------ |
| // iterationStart |
| // ------------------------------ |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2, |
| iterations: 1, |
| fill: 'both', |
| duration: 100, |
| delay: 1 }) |
| anim.play(); |
| anim.effect.updateTiming({ iterationStart: 2.5 }); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 2); |
| }, 'Allows setting the iterationStart of an animation in progress:' |
| + ' backwards-filling'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2, |
| iterations: 1, |
| fill: 'both', |
| duration: 100, |
| delay: 0 }) |
| anim.play(); |
| anim.effect.updateTiming({ iterationStart: 2.5 }); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 2); |
| }, 'Allows setting the iterationStart of an animation in progress:' |
| + ' active phase'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.3, |
| iterations: 1, |
| fill: 'both', |
| duration: 200, |
| delay: 0 }) |
| anim.play(); |
| assert_percents_equal(anim.currentTime, 0); |
| assert_percents_equal(anim.effect.getComputedTiming().localTime, 0, "localTime"); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.3); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0); |
| |
| anim.finish(); |
| assert_percents_equal(anim.currentTime, 100); |
| assert_percents_equal(anim.effect.getComputedTiming().localTime, 100, "localTime"); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.3); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 1); |
| |
| anim.effect.updateTiming({ iterationStart: 2.5 }); |
| assert_percents_equal(anim.currentTime, 100); |
| assert_percents_equal(anim.effect.getComputedTiming().localTime, 100, "localTime"); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 3); |
| }, 'Allows setting the iterationStart of an animation in progress:' |
| + ' forwards-filling'); |
| |
| for (const invalid of gBadIterationStartValues) { |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t) |
| anim.play(); |
| assert_throws_js(TypeError, () => { |
| anim.effect.updateTiming({ iterationStart: invalid }); |
| }, `setting ${invalid}`); |
| }, `Throws when setting invalid iterationStart value: ${invalid}`); |
| } |
| |
| // ------------------------------ |
| // iterations |
| // ------------------------------ |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| anim.effect.updateTiming({ iterations: 2 }); |
| assert_equals(anim.effect.getTiming().iterations, 2, 'set duration 2'); |
| assert_equals(anim.effect.getComputedTiming().iterations, 2, |
| 'getComputedTiming() after set iterations 2'); |
| }, 'Allows setting iterations to a double value'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| assert_throws_js(TypeError, () => { |
| anim.effect.updateTiming({ iterations: Infinity }); |
| }, "test"); |
| }, `Throws when setting iterations to Infinity`); |
| |
| |
| // progress based animations behave a bit differently than time based animations |
| // when changing iterations. |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000, fill: 'both' }) |
| anim.play(); |
| anim.finish(); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress when animation is finished'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 100, |
| 'duration when animation is finished'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0, |
| 'current iteration when animation is finished'); |
| |
| anim.effect.updateTiming({ iterations: 2 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after adding an iteration'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 50, |
| 'duration after adding an iteration'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 1, |
| 'current iteration after adding an iteration'); |
| |
| anim.effect.updateTiming({ iterations: 4 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after setting iterations to 4'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 25, |
| 'duration after setting iterations to 4'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 3, |
| 'current iteration after setting iterations to 4'); |
| |
| anim.effect.updateTiming({ iterations: 0 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 0, |
| 'progress after setting iterations to zero'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 0, |
| 'duration after setting iterations to zero'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0, |
| 'current iteration after setting iterations to zero'); |
| }, 'Allows setting the iterations of an animation in progress'); |
| |
| // Added test for checking duration "auto" |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'both' }) |
| anim.play(); |
| anim.finish(); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress when animation is finished'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 100, |
| 'duration when animation is finished'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0, |
| 'current iteration when animation is finished'); |
| |
| anim.effect.updateTiming({ iterations: 2 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after adding an iteration'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 50, |
| 'duration after adding an iteration'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 1, |
| 'current iteration after adding an iteration'); |
| |
| anim.effect.updateTiming({ iterations: 4 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after setting iterations to 4'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 25, |
| 'duration after setting iterations to 4'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 3, |
| 'current iteration after setting iterations to 4'); |
| |
| anim.effect.updateTiming({ iterations: 0 }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 0, |
| 'progress after setting iterations to zero'); |
| assert_percents_equal(anim.effect.getComputedTiming().duration, 0, |
| 'duration after setting iterations to zero'); |
| assert_equals(anim.effect.getComputedTiming().currentIteration, 0, |
| 'current iteration after setting iterations to zero'); |
| }, 'Allows setting the iterations of an animation in progress with duration "auto"'); |
| |
| |
| // ------------------------------ |
| // duration |
| // ------------------------------ |
| // adapted for progress based animations |
| const gGoodDurationValuesForProgressBased = [ |
| // until duration returns a CSSNumberish which can handle percentages, 100% |
| // will be represented as 100 |
| { specified: 123.45, computed: 100 }, |
| { specified: 'auto', computed: 100 }, |
| ]; |
| |
| for (const duration of gGoodDurationValuesForProgressBased) { |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, 2000) |
| anim.play(); |
| anim.effect.updateTiming({ duration: duration.specified }); |
| if (typeof duration.specified === 'number') { |
| assert_time_equals_literal(anim.effect.getTiming().duration, |
| duration.specified, |
| 'Updates specified duration'); |
| } else { |
| assert_equals(anim.effect.getTiming().duration, duration.specified, |
| 'Updates specified duration'); |
| } |
| assert_percents_equal(anim.effect.getComputedTiming().duration, |
| duration.computed, |
| 'Updates computed duration'); |
| }, `Allows setting the duration to ${duration.specified}`); |
| } |
| |
| // adapted for progress based animations |
| const gBadDurationValuesForProgressBased = [ |
| -1, NaN, Infinity, -Infinity, 'abc', '100' |
| ]; |
| |
| for (const invalid of gBadDurationValuesForProgressBased) { |
| test(t => { |
| assert_throws_js(TypeError, () => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: invalid }) |
| anim.play(); |
| }); |
| }, 'Throws when setting invalid duration: ' |
| + (typeof invalid === 'string' ? `"${invalid}"` : invalid)); |
| } |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000, fill: 'both' }) |
| anim.play(); |
| anim.finish(); |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress when animation is finished'); |
| anim.effect.updateTiming({ duration: anim.effect.getTiming().duration * 2 }); |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 1, |
| 'progress after doubling the duration'); |
| anim.effect.updateTiming({ duration: 0 }); |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after setting duration to zero'); |
| anim.effect.updateTiming({ duration: 'auto' }); |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after setting duration to \'auto\''); |
| }, 'Allows setting the duration of an animation in progress'); |
| |
| promise_test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000, fill: 'both' }) |
| anim.play(); |
| return anim.ready.then(() => { |
| const originalStartTime = anim.startTime; |
| const originalCurrentTime = anim.currentTime; |
| assert_percents_equal( |
| anim.effect.getComputedTiming().duration, |
| 100, |
| 'Initial duration should be as set on KeyframeEffect' |
| ); |
| |
| anim.effect.updateTiming({ duration: 200000 }); |
| assert_percents_equal( |
| anim.effect.getComputedTiming().duration, |
| 100, |
| 'Effect duration should remain at 100% for progress based animations' |
| ); |
| assert_percents_equal(anim.startTime, originalStartTime, |
| 'startTime should be unaffected by changing effect ' + |
| 'duration'); |
| |
| assert_percents_equal(anim.currentTime, originalCurrentTime, |
| 'currentTime should be unaffected by changing ' + |
| 'effect duration'); |
| }); |
| }, 'Allows setting the duration of an animation in progress such that the' + |
| ' the start and current time do not change'); |
| |
| |
| // ------------------------------ |
| // direction |
| // ------------------------------ |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 }) |
| anim.play(); |
| |
| const directions = ['normal', 'reverse', 'alternate', 'alternate-reverse']; |
| for (const direction of directions) { |
| anim.effect.updateTiming({ direction: direction }); |
| assert_equals(anim.effect.getTiming().direction, direction, |
| `set direction to ${direction}`); |
| } |
| }, 'Allows setting the direction to each of the possible keywords'); |
| |
| promise_test(async t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' }); |
| |
| const scroller = anim.timeline.source; |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| anim.play(); |
| await anim.ready; |
| scroller.scrollTop = maxScroll * 0.07 |
| await waitForNextFrame(); |
| |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.07, |
| 'progress before updating direction'); |
| |
| anim.effect.updateTiming({ direction: 'reverse' }); |
| |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.93, |
| 'progress after updating direction'); |
| }, 'Allows setting the direction of an animation in progress from \'normal\' to' |
| + ' \'reverse\''); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' }); |
| anim.play(); |
| assert_equals(anim.effect.getComputedTiming().progress, 0, |
| 'progress before updating direction'); |
| |
| anim.effect.updateTiming({ direction: 'reverse' }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after updating direction'); |
| }, 'Allows setting the direction of an animation in progress from \'normal\' to' |
| + ' \'reverse\' while at start of active interval'); |
| |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'backwards', |
| duration: 10000, |
| delay: 10000, |
| direction: 'normal' }); |
| anim.play(); |
| assert_equals(anim.effect.getComputedTiming().progress, 0, |
| 'progress before updating direction'); |
| |
| anim.effect.updateTiming({ direction: 'reverse' }); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'progress after updating direction'); |
| }, 'Allows setting the direction of an animation in progress from \'normal\' to' |
| + ' \'reverse\' while filling backwards'); |
| |
| promise_test(async t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2, |
| duration: 10000, |
| direction: 'normal' }); |
| const scroller = anim.timeline.source; |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| anim.play(); |
| await anim.ready; |
| scroller.scrollTop = maxScroll * 0.17 // 34% through first iteration |
| await waitForNextFrame(); |
| |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34, |
| 'progress before updating direction'); |
| |
| anim.effect.updateTiming({ direction: 'alternate' }); |
| |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34, |
| 'progress after updating direction'); |
| }, 'Allows setting the direction of an animation in progress from \'normal\' to' |
| + ' \'alternate\''); |
| |
| promise_test(async t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2, |
| duration: 10000, |
| direction: 'alternate' }); |
| const scroller = anim.timeline.source; |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| anim.play(); |
| await anim.ready; |
| scroller.scrollTop = maxScroll * 0.17 |
| await waitForNextFrame(); |
| // anim.currentTime = 17000; // 34% through first iteration |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34, |
| 'progress before updating direction'); |
| |
| anim.effect.updateTiming({ direction: 'alternate-reverse' }); |
| |
| assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.66, |
| 'progress after updating direction'); |
| }, 'Allows setting the direction of an animation in progress from \'alternate\'' |
| + ' to \'alternate-reverse\''); |
| |
| |
| // ------------------------------ |
| // easing |
| // ------------------------------ |
| |
| async function assert_progress(animation, scrollPercent, easingFunction) { |
| const scroller = animation.timeline.source; |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| scroller.scrollTop = maxScroll * scrollPercent |
| await waitForNextFrame(); |
| assert_approx_equals(animation.effect.getComputedTiming().progress, |
| easingFunction(scrollPercent), |
| 0.01, |
| 'The progress of the animation should be approximately' |
| + ` ${easingFunction(scrollPercent)} at ${scrollPercent}%`); |
| } |
| |
| for (const options of gEasingTests) { |
| promise_test(async t => { |
| const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000, |
| fill: 'forwards' }); |
| anim.play(); |
| anim.effect.updateTiming({ easing: options.easing }); |
| assert_equals(anim.effect.getTiming().easing, |
| options.serialization || options.easing); |
| |
| const easing = options.easingFunction; |
| await assert_progress(anim, 0, easing); |
| await assert_progress(anim, 0.25, easing); |
| await assert_progress(anim, 0.5, easing); |
| await assert_progress(anim, 0.75, easing); |
| await assert_progress(anim, 1, easing); |
| }, `Allows setting the easing to a ${options.desc}`); |
| } |
| |
| for (const easing of gRoundtripEasings) { |
| test(t => { |
| const anim = createScrollLinkedAnimationWithTiming(t); |
| anim.play(); |
| anim.effect.updateTiming({ easing: easing }); |
| assert_equals(anim.effect.getTiming().easing, easing); |
| }, `Updates the specified value when setting the easing to '${easing}'`); |
| } |
| |
| // Because of the delay being so large, this progress based animation is always |
| // in the finished state with progress 1. Included here because it is in the |
| // original test file for time based animations. |
| promise_test(async t => { |
| const delay = 1000000; |
| |
| const anim = createScrollLinkedAnimationWithTiming(t, |
| { duration: 1000000, fill: 'both', delay: delay, easing: 'steps(2, start)' }); |
| |
| const scroller = anim.timeline.source; |
| const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| anim.play(); |
| await anim.ready; |
| |
| anim.effect.updateTiming({ easing: 'steps(2, end)' }); |
| assert_equals(anim.effect.getComputedTiming().progress, 0, |
| 'easing replace to steps(2, end) at before phase'); |
| |
| scroller.scrollTop = maxScroll * 0.875 |
| await waitForNextFrame(); |
| |
| assert_equals(anim.effect.getComputedTiming().progress, 0.5, |
| 'change currentTime to active phase'); |
| |
| anim.effect.updateTiming({ easing: 'steps(2, start)' }); |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'easing replace to steps(2, start) at active phase'); |
| |
| scroller.scrollTop = maxScroll * 1.25 |
| await waitForNextFrame(); |
| |
| anim.effect.updateTiming({ easing: 'steps(2, end)' }); |
| assert_equals(anim.effect.getComputedTiming().progress, 1, |
| 'easing replace to steps(2, end) again at after phase'); |
| }, 'Allows setting the easing of an animation in progress'); |
| </script> |
| </body> |