tor-browser

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

event-order.tentative.html (8226B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>Tests for CSS animation event order</title>
      4 <link rel="help" href="https://drafts.csswg.org/css-animations-2/#event-dispatch"/>
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="support/testcommon.js"></script>
      8 <style>
      9 @keyframes anim {
     10  from { margin-left: 0px; }
     11  to { margin-left: 100px; }
     12 }
     13 @keyframes color-anim {
     14  from { color: red; }
     15  to { color: green; }
     16 }
     17 </style>
     18 <div id="log"></div>
     19 <script type='text/javascript'>
     20 'use strict';
     21 
     22 /**
     23 * Asserts that the set of actual and received events match.
     24 * @param actualEvents   An array of the received AnimationEvent objects.
     25 * @param expectedEvents A series of array objects representing the expected
     26 *        events, each having the form:
     27 *          [ event type, target element, [pseudo type], elapsed time ]
     28 */
     29 const checkEvents = (actualEvents, ...expectedEvents) => {
     30  const actualTypeSummary = actualEvents.map(event => event.type).join(', ');
     31  const expectedTypeSummary = expectedEvents.map(event => event[0]).join(', ');
     32 
     33  assert_equals(
     34    actualEvents.length,
     35    expectedEvents.length,
     36    `Number of events received (${actualEvents.length}) \
     37 should match expected number (${expectedEvents.length}) \
     38 (expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
     39  );
     40 
     41  for (const [index, actualEvent] of actualEvents.entries()) {
     42    const expectedEvent = expectedEvents[index];
     43    const [type, target] = expectedEvent;
     44    const pseudoElement = expectedEvent.length === 4 ? expectedEvent[2] : '';
     45    const elapsedTime = expectedEvent[expectedEvent.length - 1];
     46 
     47    assert_equals(
     48      actualEvent.type,
     49      type,
     50      `Event #${index + 1} types should match \
     51 (expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
     52    );
     53    assert_equals(
     54      actualEvent.target,
     55      target,
     56      `Event #${index + 1} targets should match`
     57    );
     58    assert_equals(
     59      actualEvent.pseudoElement,
     60      pseudoElement,
     61      `Event #${index + 1} pseudoElements should match`
     62    );
     63    assert_equals(
     64      actualEvent.elapsedTime,
     65      elapsedTime,
     66      `Event #${index + 1} elapsedTimes should match`
     67    );
     68  }
     69 };
     70 
     71 const setupAnimation = (t, animationStyle, receiveEvents) => {
     72  const div = addDiv(t, { style: 'animation: ' + animationStyle });
     73 
     74  for (const name of ['start', 'iteration', 'end']) {
     75    div['onanimation' + name] = evt => {
     76      receiveEvents.push({
     77        type: evt.type,
     78        target: evt.target,
     79        pseudoElement: evt.pseudoElement,
     80        elapsedTime: evt.elapsedTime,
     81      });
     82    };
     83  }
     84 
     85  const watcher = new EventWatcher(t, div, [
     86    'animationstart',
     87    'animationiteration',
     88    'animationend',
     89  ]);
     90 
     91  const animation = div.getAnimations()[0];
     92 
     93  return [animation, watcher, div];
     94 };
     95 
     96 promise_test(async t => {
     97  let events = [];
     98  const [animation1, watcher1, div1] =
     99    setupAnimation(t, 'anim 100s 2 paused', events);
    100  const [animation2, watcher2, div2] =
    101    setupAnimation(t, 'anim 100s 2 paused', events);
    102 
    103  await Promise.all([ watcher1.wait_for('animationstart'),
    104                      watcher2.wait_for('animationstart') ]);
    105 
    106  checkEvents(events, ['animationstart', div1, 0],
    107                      ['animationstart', div2, 0]);
    108 
    109  events.length = 0;  // Clear received event array
    110 
    111  animation1.currentTime = 100 * MS_PER_SEC;
    112  animation2.currentTime = 100 * MS_PER_SEC;
    113 
    114  await Promise.all([ watcher1.wait_for('animationiteration'),
    115                      watcher2.wait_for('animationiteration') ]);
    116 
    117  checkEvents(events, ['animationiteration', div1, 100],
    118                      ['animationiteration', div2, 100]);
    119 
    120  events.length = 0;  // Clear received event array
    121 
    122  animation1.finish();
    123  animation2.finish();
    124 
    125  await Promise.all([ watcher1.wait_for('animationend'),
    126                      watcher2.wait_for('animationend') ]);
    127 
    128  checkEvents(events, ['animationend', div1, 200],
    129                      ['animationend', div2, 200]);
    130 }, 'Same events are ordered by elements');
    131 
    132 function pseudoTest(description, testMarkerPseudos) {
    133  promise_test(async t => {
    134    // Setup a hierarchy as follows:
    135    //
    136    //              parent
    137    //                |
    138    //  (::marker, ::before, ::after) // ::marker optional
    139    //                |
    140    //              child
    141    const parentDiv = addDiv(t, { style: 'animation: anim 100s' });
    142 
    143    parentDiv.id = 'parent-div';
    144    addStyle(t, {
    145      '#parent-div::after': "content: ''; animation: anim 100s",
    146      '#parent-div::before': "content: ''; animation: anim 100s",
    147    });
    148 
    149    if (testMarkerPseudos) {
    150      parentDiv.style.display = 'list-item';
    151      addStyle(t, {
    152        '#parent-div::marker': "content: ''; animation: color-anim 100s",
    153      });
    154    }
    155 
    156    const childDiv = addDiv(t, { style: 'animation: anim 100s' });
    157    parentDiv.append(childDiv);
    158 
    159    // Setup event handlers
    160    let events = [];
    161    for (const name of ['start', 'iteration', 'end', 'cancel']) {
    162      parentDiv['onanimation' + name] = evt => {
    163        events.push({
    164          type: evt.type,
    165          target: evt.target,
    166          pseudoElement: evt.pseudoElement,
    167          elapsedTime: evt.elapsedTime,
    168        });
    169      };
    170    }
    171 
    172    // Wait a couple of frames for the events to be dispatched
    173    await waitForFrame();
    174    await waitForFrame();
    175 
    176    const expectedEvents = [
    177      ['animationstart', parentDiv, 0],
    178      ['animationstart', parentDiv, '::marker', 0],
    179      ['animationstart', parentDiv, '::before', 0],
    180      ['animationstart', parentDiv, '::after', 0],
    181      ['animationstart', childDiv, 0],
    182    ];
    183    if (!testMarkerPseudos) {
    184      expectedEvents.splice(1, 1);
    185    }
    186 
    187    checkEvents(events, ...expectedEvents);
    188  }, description);
    189 }
    190 
    191 pseudoTest('Same events on pseudo-elements follow the prescribed order', false);
    192 pseudoTest('Same events on pseudo-elements follow the prescribed order ' +
    193    '(::marker)', true);
    194 
    195 promise_test(async t => {
    196  let events = [];
    197  const [animation1, watcher1, div1] =
    198    setupAnimation(t, 'anim 200s 400s', events);
    199  const [animation2, watcher2, div2] =
    200    setupAnimation(t, 'anim 300s 2', events);
    201 
    202  await watcher2.wait_for('animationstart');
    203 
    204  animation1.currentTime = 400 * MS_PER_SEC;
    205  animation2.currentTime = 400 * MS_PER_SEC;
    206 
    207  events.length = 0;  // Clear received event array
    208 
    209  await Promise.all([ watcher1.wait_for('animationstart'),
    210                      watcher2.wait_for('animationiteration') ]);
    211 
    212  checkEvents(events, ['animationiteration', div2, 300],
    213                      ['animationstart',     div1, 0]);
    214 }, 'Start and iteration events are ordered by time');
    215 
    216 promise_test(async t => {
    217  let events = [];
    218  const [animation1, watcher1, div1] =
    219    setupAnimation(t, 'anim 150s', events);
    220  const [animation2, watcher2, div2] =
    221    setupAnimation(t, 'anim 100s 2', events);
    222 
    223  await Promise.all([ watcher1.wait_for('animationstart'),
    224                      watcher2.wait_for('animationstart') ]);
    225 
    226  animation1.currentTime = 150 * MS_PER_SEC;
    227  animation2.currentTime = 150 * MS_PER_SEC;
    228 
    229  events.length = 0;  // Clear received event array
    230 
    231  await Promise.all([ watcher1.wait_for('animationend'),
    232                      watcher2.wait_for('animationiteration') ]);
    233 
    234  checkEvents(events, ['animationiteration', div2, 100],
    235                      ['animationend',       div1, 150]);
    236 }, 'Iteration and end events are ordered by time');
    237 
    238 promise_test(async t => {
    239  let events = [];
    240  const [animation1, watcher1, div1] =
    241    setupAnimation(t, 'anim 100s 100s', events);
    242  const [animation2, watcher2, div2] =
    243    setupAnimation(t, 'anim 100s 2', events);
    244 
    245  animation1.finish();
    246  animation2.finish();
    247 
    248  await Promise.all([ watcher1.wait_for([ 'animationstart',
    249                                          'animationend' ]),
    250                      watcher2.wait_for([ 'animationstart',
    251                                          'animationend' ]) ]);
    252 
    253  checkEvents(events, ['animationstart', div2, 0],
    254                      ['animationstart', div1, 0],
    255                      ['animationend',   div1, 100],
    256                      ['animationend',   div2, 200]);
    257 }, 'Start and end events are sorted correctly when fired simultaneously');
    258 
    259 </script>