chromium/third_party/blink/web_tests/fast/scrolling/scrollend-event-fired-keyboard-scrolling.html

<!doctype html>
<html>

<head>
  <script src="../../resources/testharness.js"></script>
  <script src="../../resources/testharnessreport.js"></script>
  <script src="../../resources/gesture-util.js"></script>
  <script src="../../resources/testdriver.js"></script>
  <script src="../../resources/testdriver-vendor.js"></script>

  <style>
    #target {
      border: 1px solid black;
      height: 400px;
      width: 400px;
      overflow-y: scroll;
      resize: both;
    }

    .spacer {
      height: 2000px;
      width: 100%;
    }
  </style>
</head>

<body onload=runTest()>
  <div id="target">
    <button id="targetButton">target</button>
    <div class="spacer"></div>
  </div>
  <button id="docButton">doc</button>
  <div class="spacer"></div>

  <script>
    let target_div = document.getElementById("target");

    async function scrollDownElement(element, num_keydowns) {
      const arrowDown = '\uE015';
      for (let i = 0; i < num_keydowns; i++) {
        await test_driver.send_keys(element, arrowDown);
      }
    }

    async function scrollUpElement(element, num_keydowns) {
      const arrowUp = '\uE013';
      for (let i = 0; i < num_keydowns; i++) {
        await test_driver.send_keys(element, arrowUp);
      }
    }

    async function testSingleScrollendFired(test, scrolling_element, listening_element, button_element) {
      await waitForCompositorCommit();
      // This test ensures that only one scrollend fires when scrolling an element
      // from scrollTop=|target_offset| to scrollTop=0.
      // |target_offset| is calculated to be a scroll offset large enough to
      // require multiple key downs.
      await waitForScrollReset(scrolling_element);
      assert_equals(scrolling_element.scrollTop, 0, "element should not be scrolled");

      let target_scrollend_promise = waitForScrollendEvent(listening_element);
      // Buttons are capable of grabbing input focus so they provide a
      // consistent mechanism for targeting key events.
      await scrollDownElement(button_element, 1);
      await target_scrollend_promise;
      let single_keydown_offset = scrolling_element.scrollTop;
      assert_greater_than(single_keydown_offset, 0, "should have non-zero scroll offset");

      let target_offset = 3 * single_keydown_offset;
      target_scrollend_promise = waitForScrollendEvent(listening_element);
      scrolling_element.scrollTop = target_offset;
      await target_scrollend_promise;
      assert_equals(scrolling_element.scrollTop, target_offset);

      target_scrollend_promise = waitForScrollendEvent(listening_element);
      await scrollUpElement(button_element, 5);
      await target_scrollend_promise;
      // If scrollend fired prematurely, we would see non-zero scrolltop.
      assert_equals(scrolling_element.scrollTop, 0, "element should be scrolled all the way back up.");
    }

    function runTest() {
      if (!window.internals)
        return;

      internals.settings.setScrollAnimatorEnabled(true);

      promise_test(async (t) => {
        await testSingleScrollendFired(t, target_div, target_div, targetButton);
      }, "scrollend event fired for target element, only once.");

      promise_test(async (t) => {
        await testSingleScrollendFired(t, document.scrollingElement, document, docButton);
      }, "scrollend event fired for root scroller, only once.");
    }
  </script>
</body>

</html>