chromium/third_party/blink/web_tests/fast/compositor-wheel-scroll-latching/non-animated-scroll/subpixel-accumulation.html

<!DOCTYPE html>
<script src='../../../resources/gesture-util.js'></script>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/percent-based-util.js"></script>
<script>
  let t;
  if (window.internals && chrome && chrome.gpuBenchmarking) {
    internals.settings.setPreferCompositingToLCDTextEnabled(true);
    internals.settings.setScrollAnimatorEnabled(false);
    t = async_test("Vertical scroll shouldn't latch to horizontal scroller.");
  }

  // Helper async function to block execution for n number of rAFs.
  async function nFrames(n) {
    return new Promise(resolve => {
      let remainingFrames = n;
      let func = function() {
        --remainingFrames;
        if (remainingFrames === 0)
          resolve();
        else {
          requestAnimationFrame(func);
        }
      };

      if (n === 0) {
        resolve();
      } else {
        requestAnimationFrame(() => {
          func(resolve);
        });
      }
    });
  }

  async function runTest() {
    if (!chrome.gpuBenchmarking)
      return;
    const WHEEL_SOURCE_TYPE = GestureSourceType.MOUSE_INPUT;

    // Wait a bit to ensure we don't start sending scroll gestures to the
    // compositor before the page layers have fully propagated to the CC active
    // tree.
    await nFrames(2);

    // Scroll horizontally first. Ensure we scrolled the div since otherwise we
    // may pass the test vacuously. See crbug.com/801381 for the case we're
    // guarding against.
    const pixelsToScroll = 10;
    const { x: pixelsToScrollX, y: pixelsToScrollY } = calculatePixelsToScroll(
      document.scrollingElement, pixelsToScroll, pixelsToScroll
    );
    await smoothScroll(
      pixelsToScrollX, 50, 50, WHEEL_SOURCE_TYPE, 'right', 1000,
      false /* precise_scrolling_deltas */
    );

    // Wait a bit since the scroll gesture resolves when the ScrollEnd is sent
    // from the browser, not when it's processed by the renderer.
    await nFrames(2);

    t.step(() => {
      // Approx because smoothScrollBy isn't perfectly accurate.
      const scroller = document.getElementById("scroller");
      const { x: expectedScrollLeft } = (
        calculateExpectedScroll(scroller, pixelsToScrollX, 0)
      );
      assert_approx_equals(scroller.scrollLeft, expectedScrollLeft, 0.1,
          "Sanity check, if this fails the test isn't in the correct state.");
    });

    const { y: expectedScrollY } = (
      calculateExpectedScroll(document.scrollingElement, 0, pixelsToScrollY)
    );
    // Now scroll vertically. The scroller shouldn't have any vertical scroll
    // extent so the window should scroll.
    await smoothScroll(
      pixelsToScrollY, 50, 50, WHEEL_SOURCE_TYPE, 'down', 1000,
      false /* precise_scrolling_deltas */
    );
    await nFrames(2);
    t.step(() => {
      assert_approx_equals(window.scrollY, expectedScrollY, 0.1);
    });
    t.done();
  }

  addEventListener('load', runTest);
</script>
<style>
  ::-webkit-scrollbar {
    width: 0px;
    height: 0px;
  }
  body {
    margin: 0;
    height: 2000px;
  }
  #scroller {
    position: relative;
    top: 0.5625px;
    width: 200px;
    height: 200.8125px;
    overflow: auto;
  }
  #space {
    width: 1000px;
    background-color: coral;
    height: 200.8125px;
  }
</style>
<div id="scroller">
  <div id="space"></div>
</div>