tor-browser

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

event-dispatch.tentative.html (16872B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>CSS transition event dispatch</title>
      4 <link rel="help" href="https://drafts.csswg.org/css-transitions-2/#event-dispatch">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="support/helper.js"></script>
      8 <div id="log"></div>
      9 <script>
     10 'use strict';
     11 
     12 // All transition events should be received on the next animation frame. If
     13 // two animation frames pass before receiving the expected events then we
     14 // can immediately fail the current test.
     15 const transitionEventsTimeout = () => {
     16  return waitForAnimationFrames(2);
     17 };
     18 
     19 const setupTransition = (t, transitionStyle) => {
     20  const div = addDiv(t, { style: 'transition: ' + transitionStyle });
     21  const watcher = new EventWatcher(t, div, [ 'transitionrun',
     22                                             'transitionstart',
     23                                             'transitionend',
     24                                             'transitioncancel' ],
     25                                   transitionEventsTimeout);
     26  getComputedStyle(div).marginLeft;
     27 
     28  div.style.marginLeft = '100px';
     29  const transition = div.getAnimations()[0];
     30 
     31  return { transition, watcher, div };
     32 };
     33 
     34 // On the next frame (i.e. when events are queued), whether or not the
     35 // transition is still pending depends on the implementation.
     36 promise_test(async t => {
     37  const { transition, watcher } =
     38    setupTransition(t, 'margin-left 100s 100s');
     39  const evt = await watcher.wait_for('transitionrun');
     40  assert_equals(evt.elapsedTime, 0.0);
     41 }, 'Idle -> Pending or Before');
     42 
     43 promise_test(async t => {
     44  const { transition, watcher } =
     45    setupTransition(t, 'margin-left 100s 100s');
     46  // Force the transition to leave the idle phase
     47  transition.startTime = document.timeline.currentTime;
     48  const evt = await watcher.wait_for('transitionrun');
     49  assert_equals(evt.elapsedTime, 0.0);
     50 }, 'Idle -> Before');
     51 
     52 promise_test(async t => {
     53  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
     54 
     55  // Seek to Active phase.
     56  transition.currentTime = 100 * MS_PER_SEC;
     57  transition.pause();
     58  const events = await watcher.wait_for(['transitionrun', 'transitionstart'], {
     59    record: 'all',
     60  });
     61  assert_equals(events[0].elapsedTime, 0.0);
     62  assert_equals(events[1].elapsedTime, 0.0);
     63 }, 'Idle or Pending -> Active');
     64 
     65 promise_test(async t => {
     66  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
     67 
     68  // Seek to After phase.
     69  transition.finish();
     70  const events = await watcher.wait_for(
     71    ['transitionrun', 'transitionstart', 'transitionend'],
     72    {
     73      record: 'all',
     74    }
     75  );
     76  assert_equals(events[0].elapsedTime, 0.0);
     77  assert_equals(events[1].elapsedTime, 0.0);
     78  assert_equals(events[2].elapsedTime, 100.0);
     79 }, 'Idle or Pending -> After');
     80 
     81 promise_test(async t => {
     82  const { transition, watcher, div } =
     83    setupTransition(t, 'margin-left 100s 100s');
     84 
     85  await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
     86 
     87  // Make idle
     88  div.style.display = 'none';
     89  getComputedStyle(div).marginLeft;
     90  const evt = await watcher.wait_for('transitioncancel');
     91  assert_equals(evt.elapsedTime, 0.0);
     92 }, 'Before -> Idle (display: none)');
     93 
     94 promise_test(async t => {
     95  const { transition, watcher } =
     96    setupTransition(t, 'margin-left 100s 100s');
     97 
     98  await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
     99 
    100  // Make idle
    101  transition.timeline = null;
    102  const evt = await watcher.wait_for('transitioncancel');
    103  assert_equals(evt.elapsedTime, 0.0);
    104 }, 'Before -> Idle (Animation.timeline = null)');
    105 
    106 promise_test(async t => {
    107  const { transition, watcher } =
    108    setupTransition(t, 'margin-left 100s 100s');
    109 
    110  await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
    111 
    112  transition.currentTime = 100 * MS_PER_SEC;
    113  const evt = await watcher.wait_for('transitionstart');
    114  assert_equals(evt.elapsedTime, 0.0);
    115 }, 'Before -> Active');
    116 
    117 promise_test(async t => {
    118  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    119 
    120  await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
    121  // Seek to After phase.
    122  transition.currentTime = 200 * MS_PER_SEC;
    123  const events = await watcher.wait_for(['transitionstart', 'transitionend'], {
    124    record: 'all',
    125  });
    126 
    127  assert_equals(events[0].elapsedTime, 0.0);
    128  assert_equals(events[1].elapsedTime, 100.0);
    129 }, 'Before -> After');
    130 
    131 promise_test(async t => {
    132  const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
    133 
    134  // Seek to Active start position.
    135  transition.pause();
    136  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    137 
    138  // Make idle
    139  div.style.display = 'none';
    140  getComputedStyle(div).marginLeft;
    141  const evt = await watcher.wait_for('transitioncancel');
    142  assert_equals(evt.elapsedTime, 0.0);
    143 }, 'Active -> Idle, no delay (display: none)');
    144 
    145 promise_test(async t => {
    146  const { transition, watcher } = setupTransition(t, 'margin-left 100s');
    147 
    148  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    149 
    150  // Make idle
    151  transition.currentTime = 0;
    152  transition.timeline = null;
    153  const evt = await watcher.wait_for('transitioncancel');
    154  assert_equals(evt.elapsedTime, 0.0);
    155 }, 'Active -> Idle, no delay (Animation.timeline = null)');
    156 
    157 promise_test(async t => {
    158  const { transition, watcher, div } =
    159    setupTransition(t, 'margin-left 100s 100s');
    160  // Pause so the currentTime is fixed and we can accurately compare the event
    161  // time in transition cancel events.
    162  transition.pause();
    163 
    164  // Seek to Active phase.
    165  transition.currentTime = 100 * MS_PER_SEC;
    166  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    167 
    168  // Make idle
    169  div.style.display = 'none';
    170  getComputedStyle(div).marginLeft;
    171  const evt = await watcher.wait_for('transitioncancel');
    172  assert_equals(evt.elapsedTime, 0.0);
    173 }, 'Active -> Idle, with positive delay (display: none)');
    174 
    175 promise_test(async t => {
    176  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    177 
    178  // Seek to Active phase.
    179  transition.currentTime = 100 * MS_PER_SEC;
    180  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    181 
    182  // Make idle
    183  transition.currentTime = 100 * MS_PER_SEC;
    184  transition.timeline = null;
    185  const evt = await watcher.wait_for('transitioncancel');
    186  assert_equals(evt.elapsedTime, 0.0);
    187 }, 'Active -> Idle, with positive delay (Animation.timeline = null)');
    188 
    189 promise_test(async t => {
    190  const { transition, watcher, div } =
    191    setupTransition(t, 'margin-left 100s -50s');
    192 
    193  // Pause so the currentTime is fixed and we can accurately compare the event
    194  // time in transition cancel events.
    195  transition.pause();
    196 
    197  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    198 
    199  // Make idle
    200  div.style.display = 'none';
    201  getComputedStyle(div).marginLeft;
    202  const evt = await watcher.wait_for('transitioncancel');
    203  assert_equals(evt.elapsedTime, 50.0);
    204 }, 'Active -> Idle, with negative delay (display: none)');
    205 
    206 promise_test(async t => {
    207  const { transition, watcher } = setupTransition(t, 'margin-left 100s -50s');
    208 
    209  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    210 
    211  // Make idle
    212  transition.currentTime = 50 * MS_PER_SEC;
    213  transition.timeline = null;
    214  const evt = await watcher.wait_for('transitioncancel');
    215  assert_equals(evt.elapsedTime, 0.0);
    216 }, 'Active -> Idle, with negative delay (Animation.timeline = null)');
    217 
    218 promise_test(async t => {
    219  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    220 
    221  // Seek to Active phase.
    222  transition.currentTime = 100 * MS_PER_SEC;
    223  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    224 
    225  // Seek to Before phase.
    226  transition.currentTime = 0;
    227  const evt = await watcher.wait_for('transitionend');
    228  assert_equals(evt.elapsedTime, 0.0);
    229 }, 'Active -> Before');
    230 
    231 promise_test(async t => {
    232  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    233 
    234  // Seek to Active phase.
    235  transition.currentTime = 100 * MS_PER_SEC;
    236  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    237 
    238  // Seek to After phase.
    239  transition.currentTime = 200 * MS_PER_SEC;
    240  const evt = await watcher.wait_for('transitionend');
    241  assert_equals(evt.elapsedTime, 100.0);
    242 }, 'Active -> After');
    243 
    244 promise_test(async t => {
    245  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    246 
    247  // Seek to After phase.
    248  transition.finish();
    249  await watcher.wait_for([ 'transitionrun',
    250                           'transitionstart',
    251                           'transitionend' ]);
    252 
    253  // Seek to Before phase.
    254  transition.currentTime = 0;
    255  const events = await watcher.wait_for(['transitionstart', 'transitionend'], {
    256    record: 'all',
    257  });
    258 
    259  assert_equals(events[0].elapsedTime, 100.0);
    260  assert_equals(events[1].elapsedTime, 0.0);
    261 }, 'After -> Before');
    262 
    263 promise_test(async t => {
    264  const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
    265 
    266  // Seek to After phase.
    267  transition.finish();
    268  await watcher.wait_for([ 'transitionrun',
    269                           'transitionstart',
    270                           'transitionend' ]);
    271 
    272  // Seek to Active phase.
    273  transition.currentTime = 100 * MS_PER_SEC;
    274  const evt = await watcher.wait_for('transitionstart');
    275  assert_equals(evt.elapsedTime, 100.0);
    276 }, 'After -> Active');
    277 
    278 promise_test(async t => {
    279  const { transition, watcher } = setupTransition(t, 'margin-left 100s -50s');
    280 
    281  const events = await watcher.wait_for(['transitionrun', 'transitionstart'], {
    282    record: 'all',
    283  });
    284 
    285  assert_equals(events[0].elapsedTime, 50.0);
    286  assert_equals(events[1].elapsedTime, 50.0);
    287  transition.finish();
    288 
    289  const evt = await watcher.wait_for('transitionend');
    290  assert_equals(evt.elapsedTime, 100.0);
    291 }, 'Calculating the interval start and end time with negative start delay.');
    292 
    293 promise_test(async t => {
    294  const { transition, watcher, div } = setupTransition(
    295    t,
    296    'margin-left 100s 100s'
    297  );
    298 
    299  await watcher.wait_for('transitionrun');
    300 
    301  // We can't set the end delay via generated effect timing
    302  // because mutating CSS transitions is not specced yet.
    303  transition.effect = new KeyframeEffect(
    304    div,
    305    { marginLeft: ['0px', '100px'] },
    306    {
    307      duration: 100 * MS_PER_SEC,
    308      endDelay: -50 * MS_PER_SEC,
    309    }
    310  );
    311  // Seek to Before and play.
    312  transition.cancel();
    313  transition.play();
    314  const events = await watcher.wait_for(
    315    ['transitioncancel', 'transitionrun', 'transitionstart'],
    316    { record: 'all' }
    317  );
    318  assert_equals(events[2].elapsedTime, 0.0);
    319 
    320  // Seek to After phase.
    321  transition.finish();
    322  const evt = await watcher.wait_for('transitionend');
    323  assert_equals(evt.elapsedTime, 50.0);
    324 }, 'Calculating the interval start and end time with negative end delay.');
    325 
    326 promise_test(async t => {
    327  const { transition, watcher, div } =
    328    setupTransition(t, 'margin-left 100s 100s');
    329 
    330  await watcher.wait_for('transitionrun');
    331 
    332  // Make idle
    333  div.style.display = 'none';
    334  getComputedStyle(div).marginLeft;
    335  await watcher.wait_for('transitioncancel');
    336 
    337  transition.cancel();
    338  // Then wait a couple of frames and check that no event was dispatched
    339  await waitForAnimationFrames(2);
    340 }, 'Call Animation.cancel after canceling transition.');
    341 
    342 promise_test(async t => {
    343  const { transition, watcher, div } =
    344    setupTransition(t, 'margin-left 100s 100s');
    345 
    346  await watcher.wait_for('transitionrun');
    347 
    348  // Make idle
    349  transition.cancel();
    350  transition.play();
    351  await watcher.wait_for([ 'transitioncancel',
    352                           'transitionrun' ]);
    353 }, 'Restart transition after canceling transition immediately');
    354 
    355 promise_test(async t => {
    356  const { transition, watcher, div } =
    357    setupTransition(t, 'margin-left 100s 100s');
    358 
    359  await watcher.wait_for('transitionrun');
    360 
    361  // Make idle
    362  div.style.display = 'none';
    363  getComputedStyle(div).marginLeft;
    364  transition.play();
    365  transition.cancel();
    366  await watcher.wait_for('transitioncancel');
    367 
    368  // Then wait a couple of frames and check that no event was dispatched
    369  await waitForAnimationFrames(2);
    370 }, 'Call Animation.cancel after restarting transition immediately');
    371 
    372 promise_test(async t => {
    373  const { transition, watcher } = setupTransition(t, 'margin-left 100s');
    374 
    375  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    376 
    377  // Make idle
    378  transition.timeline = null;
    379  await watcher.wait_for('transitioncancel');
    380 
    381  transition.timeline = document.timeline;
    382  transition.play();
    383 
    384  await watcher.wait_for(['transitionrun', 'transitionstart']);
    385 }, 'Set timeline and play transition after clear the timeline');
    386 
    387 promise_test(async t => {
    388  const { transition, watcher, div } =
    389    setupTransition(t, 'margin-left 100s');
    390 
    391  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    392 
    393  transition.cancel();
    394  await watcher.wait_for('transitioncancel');
    395 
    396  // Make After phase
    397  transition.effect = null;
    398 
    399  // Then wait a couple of frames and check that no event was dispatched
    400  await waitForAnimationFrames(2);
    401 }, 'Set null target effect after canceling the transition');
    402 
    403 promise_test(async t => {
    404  const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
    405 
    406  await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
    407 
    408  transition.effect = null;
    409  await watcher.wait_for('transitionend');
    410 
    411  transition.cancel();
    412 
    413  // Then wait a couple of frames and check that no event was dispatched
    414  await waitForAnimationFrames(2);
    415 }, 'Cancel the transition after clearing the target effect');
    416 
    417 promise_test(async t => {
    418  const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
    419 
    420  // Seek to After phase.
    421  transition.finish();
    422  const events = await watcher.wait_for(
    423    ['transitionrun', 'transitionstart', 'transitionend'],
    424    {
    425      record: 'all',
    426    }
    427  );
    428 
    429  transition.cancel();
    430 
    431  // Then wait a couple of frames and check that no event was dispatched
    432  await waitForAnimationFrames(2);
    433 }, 'Cancel the transition after it finishes');
    434 
    435 promise_test(async t => {
    436  const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
    437 
    438  transition.currentTime = 50 * MS_PER_SEC;
    439  await watcher.wait_for(['transitionrun', 'transitionstart']);
    440 
    441  // Replace the running transition.
    442  div.style.marginLeft = '200px';
    443 
    444  // transitioncancel event should be fired before transitionrun because we
    445  // expect to cancel the running transition first.
    446  await watcher.wait_for(
    447    ['transitioncancel', 'transitionrun', 'transitionstart']
    448  );
    449 
    450  // Then wait a couple of frames and check that no event was dispatched
    451  await waitForAnimationFrames(2);
    452 }, 'Replacing a running transition should get transitioncancel earlier than ' +
    453   'transitionrun and transitionstart');
    454 
    455 promise_test(async t => {
    456  const div =
    457    addDiv(t, { style: 'transition: margin-left 100s, margin-top 100s' });
    458  const watcher = new EventWatcher(t, div, [ 'transitionrun',
    459                                             'transitioncancel' ],
    460                                   transitionEventsTimeout);
    461  getComputedStyle(div).marginLeft;
    462 
    463  div.style.marginLeft = '100px';
    464  div.style.marginTop = '100px';
    465  const transitions = div.getAnimations();
    466  transitions[0].currentTime = 50 * MS_PER_SEC;
    467  transitions[1].currentTime = 50 * MS_PER_SEC;
    468 
    469  await watcher.wait_for(['transitionrun', 'transitionrun']);
    470 
    471  // Replace both running transitions.
    472  div.style.marginLeft = '200px';
    473  div.style.marginTop = '200px';
    474 
    475  await watcher.wait_for([
    476    // Cancel events show first because their transition generations are
    477    // smaller than the new ones.
    478    'transitioncancel', 'transitioncancel',
    479    'transitionrun', 'transitionrun'
    480  ]);
    481 
    482  // Then wait a couple of frames and check that no event was dispatched
    483  await waitForAnimationFrames(2);
    484 }, 'Replacing two running transitions on the same target should get two ' +
    485   'transitioncancel events earlier than two transitionrun events, per ' +
    486   'transition generation');
    487 
    488 promise_test(async t => {
    489  const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
    490 
    491  transition.currentTime = 50 * MS_PER_SEC;
    492  await watcher.wait_for(['transitionrun', 'transitionstart']);
    493 
    494  // We need to wait for a while to reproduce the potential bug in Gecko.
    495  await new Promise(resolve => t.step_timeout(resolve, 100));
    496 
    497  // Replace the running transition.
    498  div.style.marginLeft = '200px';
    499  getComputedStyle(div).marginLeft;
    500 
    501  // transitioncancel event should be fired before transitionrun because we
    502  // expect to cancel the running transition first.
    503  await watcher.wait_for(
    504    ['transitioncancel', 'transitionrun', 'transitionstart']
    505  );
    506 
    507  // Then wait a couple of frames and check that no event was dispatched
    508  await waitForAnimationFrames(2);
    509 }, 'Replacing a running transition and forcing to flush the style together ' +
    510   'should get the correct event order');
    511 
    512 </script>