tor-browser

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

mouseenter-mouseleave-on-drag.html (6558B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Test for redundant mouseenter or mouseleave events</title>
      5  <script src="/resources/testharness.js"></script>
      6  <script src="/resources/testharnessreport.js"></script>
      7  <script src="/resources/testdriver.js"></script>
      8  <script src="/resources/testdriver-actions.js"></script>
      9  <script src="/resources/testdriver-vendor.js"></script>
     10 </head>
     11 <style>
     12 #outer {
     13  background: grey;
     14  width: 100px;
     15  height: 100px;
     16 }
     17 #inner {
     18  background: red;
     19  position: relative;
     20  left: 30px;
     21  top: 30px;
     22  width: 40px;
     23  height: 40px;
     24 }
     25 #done {
     26  background: green;
     27  width: 40px;
     28  height: 40px;
     29 }
     30 </style>
     31 
     32 <body>
     33  <!-- Verifies that dragging mouse in/out of an element doesn't fire redundant
     34       mouseenter or mouseleave events (crbug.com/356090 & crbug.com/470258) -->
     35  <div id="outer">
     36    <div id="inner"></div>
     37  </div>
     38  <div id="done"></div>
     39 </body>
     40 <script>
     41 let eventLog = [];
     42 let nextUncheckedEventIndex = 0;
     43 
     44 // Ensure match to the next sequence of events in the event log.
     45 function assert_next_events(target, expectedEventNames, message) {
     46  for (let i = 0; i < expectedEventNames.length; i++) {
     47    assert_true(nextUncheckedEventIndex < eventLog.length,
     48                `${message}: empty event queue`);
     49    const observed = eventLog[nextUncheckedEventIndex++];
     50    const expected = `${expectedEventNames[i]}@${target.id}`;
     51    assert_equals(observed, expected,`${message}: Event  mismatch`);
     52  }
     53 }
     54 
     55 // After validating the expected events, all entries in the event map
     56 // must be false or we have recorded an unexpected event.
     57 function assert_empty_event_queue(message) {
     58  const uncheckedEvents = eventLog.length - nextUncheckedEventIndex;
     59  assert_equals(uncheckedEvents, 0,
     60                `${message}: Unexpected events ` +
     61                `${eventLog.slice(-uncheckedEvents).join(", ")}`);
     62 }
     63 
     64 function addEventListeners(test) {
     65  const eventTypes = [
     66    'mousedown',
     67    'mouseenter',
     68    'mouseleave',
     69    'mousemove',
     70    'mouseout',
     71    'mouseover',
     72    'mouseup'
     73  ];
     74  ['inner', 'outer'].forEach(id => {
     75    const element = document.getElementById(id);
     76    eventTypes.forEach(eventType => {
     77      const listener = (e) => {
     78        if (e.eventPhase == Event.AT_TARGET) {
     79          eventLog.push(`${eventType}@${id}`);
     80        }
     81      };
     82      element.addEventListener(eventType, listener);
     83      test.add_cleanup(() => {
     84        element.removeEventListener(eventType, listener);
     85      });
     86    })
     87  });
     88 }
     89 
     90 // A click on `done` marks the end of actions in each promise_test.
     91 async function getClick(target, test) {
     92  return new Promise(resolve => {
     93    const listener = e => resolve(e);
     94    target.addEventListener('click', listener, { once: true });
     95    if (test) {
     96      test.add_cleanup(() =>
     97          target.removeEventListener('click', listener, { once: true }));
     98    }
     99  });
    100 }
    101 
    102 window.onload = async () => {
    103  const outer = document.getElementById('outer');
    104  const inner = document.getElementById('inner');
    105  const done = document.getElementById('done');
    106  const leftOuter = 0;
    107  const rightOuter = 100;
    108  const leftInner = 30;
    109  const rightInner = 70;
    110  const centerY = 50;
    111 
    112  promise_test(async t => {
    113    addEventListeners(t);
    114    const completionPromise = getClick(done, t);
    115    const actions =new test_driver.Actions();
    116    actions.pointerMove(leftOuter + 10, centerY)
    117           .pointerDown({button: actions.ButtonType.LEFT})
    118           .pointerMove(rightOuter - 10, centerY)
    119           .pointerUp({button: actions.ButtonType.LEFT})
    120           .pointerMove(0, 0, {origin: done})
    121           .pointerDown()
    122           .pointerUp()
    123           .send();
    124    await actions;
    125    await completionPromise;
    126 
    127    assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'],
    128                       'Move over outer element');
    129    assert_next_events(outer, ['mousedown', 'mousemove', 'mouseup'],
    130                       'Drag across outer element');
    131    assert_next_events(outer, ['mouseout', 'mouseleave'],
    132                       'Move to origin');
    133    assert_empty_event_queue('Drag across outer element');
    134  }, 'Test dragging across inner div');
    135 
    136  promise_test(async t => {
    137    addEventListeners(t);
    138    const completionPromise = getClick(done, t);
    139    const actions =new test_driver.Actions();
    140    actions.pointerMove(leftOuter + 10, centerY)
    141           .pointerDown({button: actions.ButtonType.LEFT})
    142           .pointerMove(leftInner + 10, centerY)
    143           .pointerUp({button: actions.ButtonType.LEFT})
    144           .pointerMove(0, 0, {origin: done})
    145           .pointerDown()
    146           .pointerUp()
    147           .send();
    148    await actions;
    149    await completionPromise;
    150 
    151    assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'],
    152                       'Move over outer element');
    153    assert_next_events(outer, ['mousedown', 'mouseout'],
    154                       'Initiate drag');
    155    assert_next_events(inner,
    156                       ['mouseover', 'mouseenter', 'mousemove', 'mouseup'],
    157                       'Drag into inner element');
    158    assert_next_events(inner, ['mouseout', 'mouseleave'],
    159                       'Move to origin');
    160    assert_next_events(outer, [ 'mouseleave'],
    161                       'Move to origin');
    162    assert_empty_event_queue('Drag into inner element');
    163  }, 'Test dragging into inner div');
    164 
    165  promise_test(async t => {
    166    addEventListeners(t);
    167    const completionPromise = getClick(done, t);
    168    const actions =new test_driver.Actions();
    169    actions.pointerMove(leftInner + 10, centerY)
    170           .pointerDown({button: actions.ButtonType.LEFT})
    171           .pointerMove(rightInner + 10, centerY)
    172           .pointerUp({button: actions.ButtonType.LEFT})
    173           .pointerMove(0, 0, {origin: done})
    174           .pointerDown()
    175           .pointerUp()
    176           .send();
    177    await actions;
    178    await completionPromise;
    179 
    180    assert_next_events(inner, ['mouseover'], 'Move over inner element');
    181    assert_next_events(outer, ['mouseenter'], 'Enter outer');
    182    assert_next_events(inner, ['mouseenter', 'mousemove'],
    183                              'Move across inner element');
    184    assert_next_events(inner, ['mousedown', 'mouseout', 'mouseleave'],
    185                              'Drag out of inner');
    186    assert_next_events(outer, ['mouseover', 'mousemove', 'mouseup'],
    187                               'Drag into outer');
    188    assert_next_events(outer, ['mouseout', 'mouseleave'],
    189                               'Move to origin');
    190    assert_empty_event_queue('Drag into inner element');
    191  }, 'Test dragging out of inner div');
    192 };
    193 </script>
    194 </html>