tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

effect-updateTiming.html (25561B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>Scroll based animation: AnimationEffect.updateTiming</title>
      4 <!-- Adapted to progressed based scroll animations from "wpt\web-animations\interfaces\AnimationEffect\updateTiming.html" -->
      5 <link rel="help" href="https://drafts.csswg.org/web-animations-1/#dom-animationeffect-updatetiming">
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="/web-animations/testcommon.js"></script>
      9 <script src="testcommon.js"></script>
     10 <script src="/web-animations/resources/easing-tests.js"></script>
     11 <script src="/web-animations/resources/timing-tests.js"></script>
     12 <style>
     13  .scroller {
     14    overflow: auto;
     15    height: 100px;
     16    width: 100px;
     17    will-change: transform;
     18  }
     19  .contents {
     20    height: 1000px;
     21    width: 100%;
     22  }
     23 </style>
     24 <body>
     25 <div id="log"></div>
     26 <script>
     27 'use strict';
     28 
     29 // ------------------------------
     30 //  delay
     31 // ------------------------------
     32 
     33 promise_test(async t => {
     34  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 1000, delay: 200})
     35  anim.play();
     36 
     37  assert_equals(anim.effect.getTiming().delay, 200, 'initial delay 200');
     38  assert_equals(anim.effect.getComputedTiming().delay, 200,
     39                'getComputedTiming() initially delay 200');
     40 
     41  anim.effect.updateTiming({ delay: 100 });
     42  assert_equals(anim.effect.getTiming().delay, 100, 'set delay 100');
     43  assert_equals(anim.effect.getComputedTiming().delay, 100,
     44                'getComputedTiming() after set delay 100');
     45 }, 'Allows setting the delay to a positive number');
     46 
     47 test(t => {
     48  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100, delay: -100})
     49  anim.play();
     50  anim.effect.updateTiming({ delay: -100 });
     51  assert_equals(anim.effect.getTiming().delay, -100, 'set delay -100');
     52  assert_equals(anim.effect.getComputedTiming().delay, -100,
     53                'getComputedTiming() after set delay -100');
     54  assert_percents_equal(anim.effect.getComputedTiming().endTime, 0,
     55                        'getComputedTiming().endTime after set delay -100');
     56 }, 'Allows setting the delay to a negative number');
     57 
     58 promise_test(async t => {
     59  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100})
     60  anim.play();
     61  await anim.ready;
     62  anim.effect.updateTiming({ delay: 100 });
     63  assert_equals(anim.effect.getComputedTiming().progress, null);
     64  assert_equals(anim.effect.getComputedTiming().currentIteration, null);
     65 }, 'Allows setting the delay of an animation in progress: positive delay that'
     66   + ' causes the animation to be no longer in-effect');
     67 
     68 promise_test(async t => {
     69  const anim =
     70      createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 });
     71  anim.play();
     72  await anim.ready;
     73  anim.effect.updateTiming({ delay: -50 });
     74  assert_equals(anim.effect.getComputedTiming().progress, 0.5);
     75 }, 'Allows setting the delay of an animation in progress: negative delay that'
     76   + ' seeks into the active interval');
     77 
     78 promise_test(async t => {
     79  const anim =
     80      createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 });
     81  anim.play();
     82  await anim.ready;
     83  anim.effect.updateTiming({ delay: -100 });
     84  assert_equals(anim.effect.getComputedTiming().progress, 1);
     85  assert_equals(anim.effect.getComputedTiming().currentIteration, 0);
     86 }, 'Allows setting the delay of an animation in progress: large negative delay'
     87   + ' that causes the animation to be finished');
     88 
     89 for (const invalid of gBadDelayValues) {
     90  test(t => {
     91  const anim = createScrollLinkedAnimationWithTiming(t)
     92  anim.play();
     93    assert_throws_js(TypeError, () => {
     94      anim.effect.updateTiming({ delay: invalid });
     95    });
     96  }, `Throws when setting invalid delay value: ${invalid}`);
     97 }
     98 
     99 
    100 // ------------------------------
    101 //  endDelay
    102 // ------------------------------
    103 
    104 promise_test(async t => {
    105  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    106  anim.play();
    107  await anim.ready;
    108  anim.effect.updateTiming({ endDelay: 123.45 });
    109  assert_time_equals_literal(anim.effect.getTiming().endDelay, 123.45,
    110                             'set endDelay 123.45');
    111  assert_time_equals_literal(anim.effect.getComputedTiming().endDelay, 123.45,
    112                             'getComputedTiming() after set endDelay 123.45');
    113 }, 'Allows setting the endDelay to a positive number');
    114 
    115 promise_test(async t => {
    116  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    117  anim.play();
    118  await anim.ready;
    119  anim.effect.updateTiming({ endDelay: -1000 });
    120  assert_equals(anim.effect.getTiming().endDelay, -1000, 'set endDelay -1000');
    121  assert_equals(anim.effect.getComputedTiming().endDelay, -1000,
    122                'getComputedTiming() after set endDelay -1000');
    123 }, 'Allows setting the endDelay to a negative number');
    124 
    125 promise_test(async t => {
    126  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    127  anim.play();
    128  await anim.ready;
    129  assert_throws_js(TypeError, () => {
    130    anim.effect.updateTiming({ endDelay: Infinity });
    131  });
    132 }, 'Throws when setting the endDelay to infinity');
    133 
    134 promise_test(async t => {
    135  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    136  anim.play();
    137  await anim.ready;
    138  assert_throws_js(TypeError, () => {
    139    anim.effect.updateTiming({ endDelay: -Infinity });
    140  });
    141 }, 'Throws when setting the endDelay to negative infinity');
    142 
    143 
    144 // ------------------------------
    145 //  fill
    146 // ------------------------------
    147 
    148 for (const fill of ['none', 'forwards', 'backwards', 'both']) {
    149  test(t => {
    150  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100 })
    151  anim.play();
    152    anim.effect.updateTiming({ fill });
    153    assert_equals(anim.effect.getTiming().fill, fill, 'set fill ' + fill);
    154    assert_equals(anim.effect.getComputedTiming().fill, fill,
    155                  'getComputedTiming() after set fill ' + fill);
    156  }, `Allows setting the fill to '${fill}'`);
    157 }
    158 
    159 
    160 // ------------------------------
    161 //  iterationStart
    162 // ------------------------------
    163 
    164 promise_test(async t => {
    165  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
    166                                      iterations: 1,
    167                                      fill: 'both',
    168                                      duration: 100,
    169                                      delay: 1 })
    170  anim.play();
    171  await anim.ready;
    172  anim.effect.updateTiming({ iterationStart: 2.5 });
    173  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5);
    174  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
    175 }, 'Allows setting the iterationStart of an animation in progress:'
    176   + ' backwards-filling');
    177 
    178 promise_test(async t => {
    179  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
    180                                      iterations: 1,
    181                                      fill: 'both',
    182                                      duration: 100,
    183                                      delay: 0 })
    184  anim.play();
    185  await anim.ready;
    186  anim.effect.updateTiming({ iterationStart: 2.5 });
    187  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5);
    188  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
    189 }, 'Allows setting the iterationStart of an animation in progress:'
    190   + ' active phase');
    191 
    192 promise_test(async t => {
    193  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.3,
    194                                      iterations: 1,
    195                                      fill: 'both',
    196                                      duration: 200,
    197                                      delay: 0 })
    198  anim.play();
    199  await anim.ready;
    200  assert_percents_equal(anim.currentTime, 0);
    201  assert_percents_equal(anim.effect.getComputedTiming().localTime, 0,
    202                        "localTime");
    203  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.3);
    204  assert_equals(anim.effect.getComputedTiming().currentIteration, 0);
    205 
    206  anim.finish();
    207  assert_percents_equal(anim.currentTime, 100);
    208  assert_percents_equal(anim.effect.getComputedTiming().localTime, 100,
    209                        "localTime");
    210  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.3);
    211  assert_equals(anim.effect.getComputedTiming().currentIteration, 1);
    212 
    213  anim.effect.updateTiming({ iterationStart: 2.5 });
    214  assert_percents_equal(anim.currentTime, 100);
    215  assert_percents_equal(anim.effect.getComputedTiming().localTime, 100,
    216                        "localTime");
    217  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.5);
    218  assert_equals(anim.effect.getComputedTiming().currentIteration, 3);
    219 }, 'Allows setting the iterationStart of an animation in progress:'
    220   + ' forwards-filling');
    221 
    222 for (const invalid of gBadIterationStartValues) {
    223  test(t => {
    224    const anim = createScrollLinkedAnimationWithTiming(t)
    225    anim.play();
    226    assert_throws_js(TypeError, () => {
    227      anim.effect.updateTiming({ iterationStart: invalid });
    228    }, `setting ${invalid}`);
    229  }, `Throws when setting invalid iterationStart value: ${invalid}`);
    230 }
    231 
    232 // ------------------------------
    233 //  iterations
    234 // ------------------------------
    235 
    236 test(t => {
    237  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    238  anim.play();
    239  anim.effect.updateTiming({ iterations: 2 });
    240  assert_equals(anim.effect.getTiming().iterations, 2, 'set duration 2');
    241  assert_equals(anim.effect.getComputedTiming().iterations, 2,
    242                'getComputedTiming() after set iterations 2');
    243 }, 'Allows setting iterations to a double value');
    244 
    245 test(t => {
    246  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    247  anim.play();
    248  assert_throws_js(TypeError, () => {
    249    anim.effect.updateTiming({ iterations: Infinity });
    250  }, "test");
    251 }, `Throws when setting iterations to Infinity`);
    252 
    253 
    254 // progress based animations behave a bit differently than time based animations
    255 // when changing iterations.
    256 test(t => {
    257  const anim =
    258      createScrollLinkedAnimationWithTiming(
    259          t, { duration: 100000, fill: 'both' });
    260  anim.play();
    261  anim.finish();
    262 
    263  assert_equals(anim.effect.getComputedTiming().progress, 1,
    264                'progress when animation is finished');
    265  assert_percents_equal(anim.effect.getComputedTiming().duration, 100,
    266                        'duration when animation is finished');
    267  assert_equals(anim.effect.getComputedTiming().currentIteration, 0,
    268                'current iteration when animation is finished');
    269 
    270  anim.effect.updateTiming({ iterations: 2 });
    271 
    272  assert_equals(anim.effect.getComputedTiming().progress, 1,
    273                'progress after adding an iteration');
    274  assert_percents_equal(anim.effect.getComputedTiming().duration, 50,
    275                        'duration after adding an iteration');
    276  assert_equals(anim.effect.getComputedTiming().currentIteration, 1,
    277                'current iteration after adding an iteration');
    278 
    279  anim.effect.updateTiming({ iterations: 4 });
    280 
    281  assert_equals(anim.effect.getComputedTiming().progress, 1,
    282                'progress after setting iterations to 4');
    283  assert_percents_equal(anim.effect.getComputedTiming().duration, 25,
    284                        'duration after setting iterations to 4');
    285  assert_equals(anim.effect.getComputedTiming().currentIteration, 3,
    286                'current iteration after setting iterations to 4');
    287 
    288  anim.effect.updateTiming({ iterations: 0 });
    289 
    290  assert_equals(anim.effect.getComputedTiming().progress, 0,
    291                'progress after setting iterations to zero');
    292  assert_percents_equal(anim.effect.getComputedTiming().duration, 0,
    293                        'duration after setting iterations to zero');
    294  assert_equals(anim.effect.getComputedTiming().currentIteration, 0,
    295                'current iteration after setting iterations to zero');
    296 }, 'Allows setting the iterations of an animation in progress');
    297 
    298 // Added test for checking duration "auto"
    299 test(t => {
    300  const anim = createScrollLinkedAnimationWithTiming(t,  { fill: 'both' });
    301  anim.play();
    302  anim.finish();
    303 
    304  assert_equals(anim.effect.getComputedTiming().progress, 1,
    305                'progress when animation is finished');
    306  assert_percents_equal(anim.effect.getComputedTiming().duration, 100,
    307                        'duration when animation is finished');
    308  assert_equals(anim.effect.getComputedTiming().currentIteration, 0,
    309                'current iteration when animation is finished');
    310 
    311  anim.effect.updateTiming({ iterations: 2 });
    312 
    313  assert_equals(anim.effect.getComputedTiming().progress, 1,
    314                'progress after adding an iteration');
    315  assert_percents_equal(anim.effect.getComputedTiming().duration, 50,
    316                        'duration after adding an iteration');
    317  assert_equals(anim.effect.getComputedTiming().currentIteration, 1,
    318                'current iteration after adding an iteration');
    319 
    320  anim.effect.updateTiming({ iterations: 4 });
    321 
    322  assert_equals(anim.effect.getComputedTiming().progress, 1,
    323                'progress after setting iterations to 4');
    324  assert_percents_equal(anim.effect.getComputedTiming().duration, 25,
    325                        'duration after setting iterations to 4');
    326  assert_equals(anim.effect.getComputedTiming().currentIteration, 3,
    327                'current iteration after setting iterations to 4');
    328 
    329  anim.effect.updateTiming({ iterations: 0 });
    330 
    331  assert_equals(anim.effect.getComputedTiming().progress, 0,
    332                'progress after setting iterations to zero');
    333  assert_percents_equal(anim.effect.getComputedTiming().duration, 0,
    334                        'duration after setting iterations to zero');
    335  assert_equals(anim.effect.getComputedTiming().currentIteration, 0,
    336                'current iteration after setting iterations to zero');
    337 }, 'Allows setting the iterations of an animation in progress with duration ' +
    338   '"auto"');
    339 
    340 
    341 // ------------------------------
    342 //  duration
    343 // ------------------------------
    344 test(t => {
    345  const anim = createScrollLinkedAnimationWithTiming(t, { duration: Infinity });
    346 }, `Allows creating scroll linked animation with duration Infinity`);
    347 
    348 // adapted for progress based animations
    349 const gGoodDurationValuesForProgressBased = [
    350  // until duration returns a CSSNumberish which can handle percentages, 100%
    351  // will be represented as 100
    352  { specified: 123.45, computed: 100 },
    353  { specified: 'auto', computed: 100 },
    354  { specified: Infinity, computed: 100 },
    355 ];
    356 
    357 for (const duration of gGoodDurationValuesForProgressBased) {
    358  test(t => {
    359    const anim = createScrollLinkedAnimationWithTiming(t, 2000);
    360    anim.play();
    361    anim.effect.updateTiming({ duration: duration.specified });
    362    if (typeof duration.specified === 'number') {
    363      assert_time_equals_literal(anim.effect.getTiming().duration,
    364                                 duration.specified,
    365                                 'Updates specified duration');
    366    } else {
    367      assert_equals(anim.effect.getTiming().duration, duration.specified,
    368                    'Updates specified duration');
    369    }
    370    assert_percents_equal(anim.effect.getComputedTiming().duration,
    371                          duration.computed,
    372                          'Updates computed duration');
    373  }, `Allows setting the duration to ${duration.specified}`);
    374 }
    375 
    376 // adapted for progress based animations
    377 const gBadDurationValuesForProgressBased = [
    378  -1, NaN, -Infinity, 'abc', '100'
    379 ];
    380 
    381 for (const invalid of gBadDurationValuesForProgressBased) {
    382  test(t => {
    383    assert_throws_js(TypeError, () => {
    384      const anim = createScrollLinkedAnimationWithTiming(t,  { duration: invalid })
    385      anim.play();
    386    });
    387  }, 'Throws when setting invalid duration: '
    388     + (typeof invalid === 'string' ? `"${invalid}"` : invalid));
    389 }
    390 
    391 test(t => {
    392  const anim =
    393      createScrollLinkedAnimationWithTiming(
    394          t, { duration: 100000, fill: 'both' });
    395  anim.play();
    396  anim.finish();
    397  assert_equals(anim.effect.getComputedTiming().progress, 1,
    398                'progress when animation is finished');
    399  anim.effect.updateTiming({ duration: anim.effect.getTiming().duration * 2 });
    400  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 1,
    401                             'progress after doubling the duration');
    402  anim.effect.updateTiming({ duration: 0 });
    403  assert_equals(anim.effect.getComputedTiming().progress, 1,
    404                'progress after setting duration to zero');
    405  anim.effect.updateTiming({ duration: 'auto' });
    406  assert_equals(anim.effect.getComputedTiming().progress, 1,
    407                'progress after setting duration to \'auto\'');
    408 }, 'Allows setting the duration of an animation in progress');
    409 
    410 promise_test(t => {
    411  const anim =
    412      createScrollLinkedAnimationWithTiming(
    413          t,  { duration: 100000, fill: 'both' });
    414  anim.play();
    415  return anim.ready.then(() => {
    416    const originalStartTime   = anim.startTime;
    417    const originalCurrentTime = anim.currentTime;
    418    assert_percents_equal(
    419      anim.effect.getComputedTiming().duration,
    420      100,
    421      'Initial duration should be as set on KeyframeEffect'
    422    );
    423 
    424    anim.effect.updateTiming({ duration: 200000 });
    425    assert_percents_equal(
    426      anim.effect.getComputedTiming().duration,
    427      100,
    428      'Effect duration should remain at 100% for progress based animations'
    429    );
    430    assert_percents_equal(anim.startTime, originalStartTime,
    431                          'startTime should be unaffected by changing effect ' +
    432                          'duration');
    433 
    434    assert_percents_equal(anim.currentTime, originalCurrentTime,
    435                          'currentTime should be unaffected by changing ' +
    436                          'effect duration');
    437  });
    438 }, 'Allows setting the duration of an animation in progress such that the' +
    439   ' the start and current time do not change');
    440 
    441 
    442 // ------------------------------
    443 //  direction
    444 // ------------------------------
    445 
    446 test(t => {
    447  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 });
    448  anim.play();
    449 
    450  const directions = ['normal', 'reverse', 'alternate', 'alternate-reverse'];
    451  for (const direction of directions) {
    452    anim.effect.updateTiming({ direction: direction });
    453    assert_equals(anim.effect.getTiming().direction, direction,
    454                  `set direction to ${direction}`);
    455  }
    456 }, 'Allows setting the direction to each of the possible keywords');
    457 
    458 promise_test(async t => {
    459  const anim =
    460      createScrollLinkedAnimationWithTiming(
    461          t, { duration: 10000, direction: 'normal' });
    462 
    463  const scroller = anim.timeline.source;
    464  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    465  anim.play();
    466  await anim.ready;
    467  scroller.scrollTop = maxScroll * 0.07
    468  await waitForNextFrame();
    469  await waitForNextFrame();
    470 
    471  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.07,
    472                             'progress before updating direction');
    473 
    474  anim.effect.updateTiming({ direction: 'reverse' });
    475 
    476  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.93,
    477                             'progress after updating direction');
    478 }, 'Allows setting the direction of an animation in progress from \'normal\' ' +
    479   'to \'reverse\'');
    480 
    481 promise_test(async t => {
    482  const anim =
    483      createScrollLinkedAnimationWithTiming(
    484          t, { duration: 10000, direction: 'normal' });
    485  anim.play();
    486  await anim.ready;
    487  assert_equals(anim.effect.getComputedTiming().progress, 0,
    488                'progress before updating direction');
    489 
    490  anim.effect.updateTiming({ direction: 'reverse' });
    491 
    492  assert_equals(anim.effect.getComputedTiming().progress, 1,
    493                'progress after updating direction');
    494 }, 'Allows setting the direction of an animation in progress from \'normal\' to'
    495   + ' \'reverse\' while at start of active interval');
    496 
    497 promise_test(async t => {
    498  const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'backwards',
    499                                      duration: 10000,
    500                                      delay: 10000,
    501                                      direction: 'normal' });
    502  anim.play();
    503  await anim.ready;
    504  assert_equals(anim.effect.getComputedTiming().progress, 0,
    505                'progress before updating direction');
    506 
    507  anim.effect.updateTiming({ direction: 'reverse' });
    508 
    509  assert_equals(anim.effect.getComputedTiming().progress, 1,
    510                'progress after updating direction');
    511 }, 'Allows setting the direction of an animation in progress from \'normal\' to'
    512   + ' \'reverse\' while filling backwards');
    513 
    514 promise_test(async t => {
    515  const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2,
    516                                      duration: 10000,
    517                                      direction: 'normal' });
    518  const scroller = anim.timeline.source;
    519  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    520  anim.play();
    521  await anim.ready;
    522  scroller.scrollTop = maxScroll * 0.17 // 34% through first iteration
    523  await waitForNextFrame();
    524  await waitForNextFrame();
    525 
    526  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34,
    527                             'progress before updating direction');
    528 
    529  anim.effect.updateTiming({ direction: 'alternate' });
    530 
    531  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34,
    532                             'progress after updating direction');
    533 }, 'Allows setting the direction of an animation in progress from \'normal\' to'
    534   + ' \'alternate\'');
    535 
    536 promise_test(async t => {
    537  const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2,
    538                                      duration: 10000,
    539                                      direction: 'alternate' });
    540  const scroller = anim.timeline.source;
    541  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    542  anim.play();
    543  await anim.ready;
    544  scroller.scrollTop = maxScroll * 0.17
    545  await waitForNextFrame();
    546  await waitForNextFrame();
    547  // anim.currentTime = 17000; // 34% through first iteration
    548  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.34,
    549                             'progress before updating direction');
    550 
    551  anim.effect.updateTiming({ direction: 'alternate-reverse' });
    552 
    553  assert_time_equals_literal(anim.effect.getComputedTiming().progress, 0.66,
    554                             'progress after updating direction');
    555 }, 'Allows setting the direction of an animation in progress from \'alternate\''
    556   + ' to \'alternate-reverse\'');
    557 
    558 
    559 // ------------------------------
    560 //  easing
    561 // ------------------------------
    562 
    563 async function assert_progress(animation, scrollPercent, easingFunction) {
    564  const scroller = animation.timeline.source;
    565  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    566  scroller.scrollTop = maxScroll * scrollPercent
    567  await waitForNextFrame();
    568  assert_approx_equals(animation.effect.getComputedTiming().progress,
    569                       easingFunction(scrollPercent),
    570                       0.01,
    571                       'The progress of the animation should be approximately'
    572                       + ` ${easingFunction(scrollPercent)} at ${scrollPercent}%`);
    573 }
    574 
    575 for (const options of gEasingTests) {
    576  promise_test(async t => {
    577    const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000,
    578                                  fill: 'forwards' });
    579    anim.play();
    580    anim.effect.updateTiming({ easing: options.easing });
    581    assert_equals(anim.effect.getTiming().easing,
    582                  options.serialization || options.easing);
    583 
    584    const easing = options.easingFunction;
    585    await assert_progress(anim, 0, easing);
    586    await assert_progress(anim, 0.25, easing);
    587    await assert_progress(anim, 0.5, easing);
    588    await assert_progress(anim, 0.75, easing);
    589    await assert_progress(anim, 1, easing);
    590  }, `Allows setting the easing to a ${options.desc}`);
    591 }
    592 
    593 for (const easing of gRoundtripEasings) {
    594  test(t => {
    595    const anim = createScrollLinkedAnimationWithTiming(t);
    596    anim.play();
    597    anim.effect.updateTiming({ easing: easing });
    598    assert_equals(anim.effect.getTiming().easing, easing);
    599  }, `Updates the specified value when setting the easing to '${easing}'`);
    600 }
    601 
    602 // Because of the delay being so large, this progress based animation is always
    603 // in the finished state with progress 1. Included here because it is in the
    604 // original test file for time based animations.
    605 promise_test(async t => {
    606  const delay = 1000000;
    607 
    608  const anim = createScrollLinkedAnimationWithTiming(t,
    609    { duration: 1000000, fill: 'both', delay: delay, easing: 'steps(2, start)' });
    610 
    611  const scroller = anim.timeline.source;
    612  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
    613  anim.play();
    614  await anim.ready;
    615 
    616  anim.effect.updateTiming({ easing: 'steps(2, end)' });
    617  assert_equals(anim.effect.getComputedTiming().progress, 0,
    618                'easing replace to steps(2, end) at before phase');
    619 
    620  scroller.scrollTop = maxScroll * 0.875
    621  await waitForNextFrame();
    622  await waitForNextFrame();
    623 
    624  assert_equals(anim.effect.getComputedTiming().progress, 0.5,
    625                'change currentTime to active phase');
    626 
    627  anim.effect.updateTiming({ easing: 'steps(2, start)' });
    628  assert_equals(anim.effect.getComputedTiming().progress, 1,
    629                'easing replace to steps(2, start) at active phase');
    630 
    631  scroller.scrollTop = maxScroll * 1.25
    632  await waitForNextFrame();
    633 
    634  anim.effect.updateTiming({ easing: 'steps(2, end)' });
    635  assert_equals(anim.effect.getComputedTiming().progress, 1,
    636                'easing replace to steps(2, end) again at after phase');
    637 }, 'Allows setting the easing of an animation in progress');
    638 </script>
    639 </body>