chromium/third_party/blink/web_tests/rootscroller/scroll-non-descendant-of-root-scroller.html

<!DOCTYPE html>
<script>
if (window.internals)
  internals.runtimeFlags.implicitRootScrollerEnabled = true;
</script>
<style>
  ::-webkit-scrollbar {
    width: 0px;
    height: 0px;
  }

  body, html {
    width: 100%;
    height: 100%;
    margin: 0px;
  }

  #rootscroller {
    width: 100%;
    height: 100%;
    overflow: auto;
  }

  #dialog {
      position: fixed;
      left: 50px;
      right: 50px;
      top: 50px;
      bottom: 50px;
      overflow: auto;
  }

  .bigspace {
      width: 2000px;
      height: 2000px;
      background-image: repeating-linear-gradient(
          45deg,
          yellow,
          yellow 80px,
          orange 80px,
          orange 160px);
  }

  .bigspace2 {
      width: 2000px;
      height: 2000px;
      background-image: repeating-linear-gradient(
          -45deg,
          blue,
          blue 80px,
          red 80px,
          red 160px);
  }

</style>

<div id="rootscroller">
  To test manually, try scrolling the red/orange box past the end. Scrolling
  shouldn't chain up to this blue/red box.
  <div class="bigspace2"></div>
</div>
<div id="dialog">
  <div class="bigspace"></div>
</div>

<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src='../resources/gesture-util.js'></script>

<script>
  var rootScroller = document.querySelector('#rootscroller');
  var dialog = document.querySelector('#dialog');

  var dialogRect = dialog.getBoundingClientRect();

  var x = dialogRect.left + dialogRect.width / 2;
  var y = dialogRect.top + dialogRect.height / 2;

  promise_test(async () => {
      await waitFor( () => { return rootScroller == internals.effectiveRootScroller(document); } );

      // Sanity check - there should be no initial scroll.
      assert_equals(dialog.scrollLeft, 0);
      assert_equals(dialog.scrollTop, 0);
      assert_equals(rootscroller.scrollLeft, 0);
      assert_equals(rootscroller.scrollTop, 0);

      // This scroll should fully scroll the dialog
      await smoothScrollWithXY(3000, 3000, x, y, GestureSourceType.TOUCH_INPUT, SPEED_INSTANT);

      await waitFor( () => { return dialog.scrollLeft == dialog.scrollWidth - dialog.clientWidth; } );

      assert_equals(dialog.scrollLeft, dialog.scrollWidth - dialog.clientWidth);
      assert_equals(dialog.scrollTop, dialog.scrollHeight - dialog.clientHeight);
      assert_equals(rootscroller.scrollLeft, 0);
      assert_equals(rootscroller.scrollTop, 0);

      // This scroll would normally chain up to the viewport but the "real"
      // viewport has no scrolling. Make sure we don't scroll the
      // document.rootScroller.
      await smoothScrollWithXY(3000, 3000, x, y, GestureSourceType.TOUCH_INPUT, SPEED_INSTANT);

      await waitFor( () => { return dialog.scrollLeft == dialog.scrollWidth - dialog.clientWidth; } );

      assert_equals(dialog.scrollLeft, dialog.scrollWidth - dialog.clientWidth);
      assert_equals(dialog.scrollTop, dialog.scrollHeight - dialog.clientHeight);
      assert_equals(rootscroller.scrollLeft, 0);
      assert_equals(rootscroller.scrollTop, 0);

  }, 'Scrolls on the dialog should not chain to the sibling root scroller.');
</script>