chromium/third_party/blink/web_tests/fast/events/dispatch-mouse-events-to-window-always.html

<!DOCTYPE html>
<style>
* {
    padding: 0;
    margin: 0;
}

::-webkit-scrollbar {
    display: none;
}

html, body {
    height: 400px;
    width: 400px;
    background: #eee;
    padding: 0;
    margin: 0;
}

div#child {
    position: absolute;
    top : 0;
    left: 400px;
    width: 400px;
    height: 10000px;
    background: #ddd;
}

</style>

<body onload="onLoad()">
    <div id='child'></div>
    <div id='console'></div>
</body>

<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/gesture-util.js"></script>
<script>
    const purpose =
    'Test that wheel and mouse events are dispatched to document ' +
    'and window even if they do not hit any element in the page.';

    window.receivers = new Map();
    const eventTypes = ['wheel', 'click', 'mousedown', 'mouseup'];
    const eventTargets = [window, document, document.body, document.getElementById('child')];

    function registerEvent(e) {
      window.receivers[e.type].push(this);
    }
    function registerEventHandlers(){
      for(var eventType of eventTypes) {
        window.receivers[eventType] = [];
        for(var target of eventTargets){
            target.addEventListener(eventType, registerEvent.bind(target));
        }
      }
    }
    function generateEventsAndVerify(x,y,expectedReceivers,title){
        promise_test(function(test){ return new Promise(async function(resolve, reject){
          await mouseDownAt(x,y);
          verifyReceivers('mousedown', expectedReceivers, test);

          await mouseUpAt(x,y);
          verifyReceivers('mouseup', expectedReceivers, test);
          verifyReceivers('click', expectedReceivers, test);

          const delta_x = 10;
          const delta_y = 10;
          const source = GestureSourceType.MOUSE_INPUT;
          const speed = SPEED_INSTANT;
          const precise_scrolling_deltas = false;
          await smoothScrollWithXY(delta_x, delta_y, x, y,
            source, speed, precise_scrolling_deltas);
          verifyReceivers('wheel', expectedReceivers, test);

          resolve();
        });}, title + ' ' + purpose);
    }
    function verifyReceivers(eventType, expectedReceivers, test) {
      window.actualReceivers = window.receivers[eventType];
      test.step(function(){
        assert_equals(objectsToString(actualReceivers), objectsToString(expectedReceivers), eventType);
      });
      window.receivers[eventType] = [];
    }
    function objectsToString(objects) {
      return String(objects.map(function(o) {return o.constructor.name;}));
    }

    function onLoad(){
      registerEventHandlers();
      // received by element, body, doc, window
      generateEventsAndVerify(500, 500, [document.getElementById('child'), document.body, document, window], 'outside body, inside element.');
      // received by body, doc, window
      generateEventsAndVerify(10, 10, [document.body, document, window], 'inside body, outside element.');
      // received by doc, window
      generateEventsAndVerify(10, 500, [document, window], 'outside body, outside element, inside frame.');
    }
</script>