Bug 1368603 - Fix intermittent scrollbar drag test failure on Linux. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 01 Aug 2018 23:25:05 -0400
changeset 825594 dba23fc2519d8c54397243cdb307f45e82371de5
parent 825566 3cb90f16402bc5e1203e2771dc93553b8377fa40
push id118145
push userkgupta@mozilla.com
push dateThu, 02 Aug 2018 03:25:45 +0000
reviewersbotond
bugs1368603
milestone63.0a1
Bug 1368603 - Fix intermittent scrollbar drag test failure on Linux. r?botond On Linux, when synthesizing mousemove events interleaved with button press/release events, the caller is responsible for waiting for the mousemove events be dispatched before attempting to synthesize the press/release buttons, otherwise the events can be delivered by the OS out of order. This updates a few tests to ensure this is done correctly. MozReview-Commit-ID: 42HkqTCWToP
gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
gfx/layers/apz/test/mochitest/apz_test_utils.js
gfx/layers/apz/test/mochitest/helper_bug1326290.html
gfx/layers/apz/test/mochitest/helper_bug1331693.html
gfx/layers/apz/test/mochitest/helper_bug1346632.html
gfx/layers/apz/test/mochitest/helper_bug1462961.html
--- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
@@ -340,18 +340,22 @@ function moveMouseAndScrollWheelOver(ele
     } else {
       synthesizeNativeWheelAndWaitForWheelEvent(element, dx, dy, 0, -10, testDriver);
     }
   });
 }
 
 // Synthesizes events to drag |element|'s vertical scrollbar by the distance
 // specified, synthesizing a mousemove for each increment as specified.
-// Returns false if the element doesn't have a vertical scrollbar, or true after
-// all the events have been synthesized.
+// Returns false if the element doesn't have a vertical scrollbar. Otherwise,
+// returns a generator that should be invoked after the mousemoves have been
+// processed by the widget code, to end the scrollbar drag. Mousemoves being
+// processed by the widget code can be detected by listening for the mousemove
+// events in the caller, or for some other event that is triggered by the
+// mousemove, such as the scroll event resulting from the scrollbar drag.
 function* dragVerticalScrollbar(element, testDriver, distance = 20, increment = 5) {
   var boundingClientRect = element.getBoundingClientRect();
   var verticalScrollbarWidth = boundingClientRect.width - element.clientWidth;
   if (verticalScrollbarWidth == 0) {
     return false;
   }
 
   var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
@@ -364,13 +368,15 @@ function* dragVerticalScrollbar(element,
   yield synthesizeNativeMouseEvent(element, mouseX, mouseY, nativeMouseMoveEventMsg(), testDriver);
   // mouse down
   yield synthesizeNativeMouseEvent(element, mouseX, mouseY, nativeMouseDownEventMsg(), testDriver);
   // drag vertically by |increment| until we reach the specified distance
   for (var y = increment; y < distance; y += increment) {
     yield synthesizeNativeMouseEvent(element, mouseX, mouseY + y, nativeMouseMoveEventMsg(), testDriver);
   }
   yield synthesizeNativeMouseEvent(element, mouseX, mouseY + distance, nativeMouseMoveEventMsg(), testDriver);
-  // and release
-  yield synthesizeNativeMouseEvent(element, mouseX, mouseY + distance, nativeMouseUpEventMsg(), testDriver);
 
-  return true;
+  // and return a generator to call afterwards to finish up the drag
+  return function*() {
+    dump("Finishing drag of #" + element.id + "\n");
+    yield synthesizeNativeMouseEvent(element, mouseX, mouseY + distance, nativeMouseUpEventMsg(), testDriver);
+  };
 }
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -232,16 +232,18 @@ function runSubtestsSeriallyInFreshWindo
       test = aSubtests[testIndex];
 
       if (onlyOneSubtest && onlyOneSubtest != test.file) {
         SimpleTest.ok(true, "Skipping " + test.file + " because only " + onlyOneSubtest + " is being run");
         setTimeout(function() { advanceSubtestExecution(); }, 0);
         return;
       }
 
+      SimpleTest.ok(true, "Starting subtest " + test.file);
+
       if (typeof test.dp_suppression != 'undefined') {
         // Normally during a test, the displayport will get suppressed during page
         // load, and unsuppressed at a non-deterministic time during the test. The
         // unsuppression can trigger a repaint which interferes with the test, so
         // to avoid that we can force the displayport to be unsuppressed for the
         // entire test which is more deterministic.
         SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(test.dp_suppression);
       }
--- a/gfx/layers/apz/test/mochitest/helper_bug1326290.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1326290.html
@@ -19,27 +19,29 @@
     }
   </style>
   <script type="text/javascript">
 
 function* test(testDriver) {
   var scrollableDiv = document.getElementById('scrollable');
   scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
 
-  var scrolled = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
-  if (!scrolled) {
+  var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
+  if (!dragFinisher) {
     ok(true, "No scrollbar, can't do this test");
     return;
   }
 
   // the events above might be stuck in APZ input queue for a bit until the
   // layer is activated, so we wait here until the scroll event listener is
   // triggered.
   yield;
 
+  yield* dragFinisher();
+
   // Flush everything just to be safe
   yield flushApzRepaints(testDriver);
 
   // After dragging the scrollbar 20px on a 200px-high scrollable div, we should
   // have scrolled approx 10% of the 2000px high content. There might have been
   // scroll arrows and such so let's just have a minimum bound of 50px to be safe.
   ok(scrollableDiv.scrollTop > 50, "Scrollbar drag resulted in a scroll position of " + scrollableDiv.scrollTop);
 }
--- a/gfx/layers/apz/test/mochitest/helper_bug1331693.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1331693.html
@@ -8,27 +8,29 @@
   <script type="application/javascript" src="apz_test_utils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <script type="text/javascript">
 
 function* test(testDriver) {
   var scrollableDiv = document.getElementById('scrollable');
   scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
 
-  var scrolled = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
-  if (!scrolled) {
+  var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
+  if (!dragFinisher) {
     ok(true, "No scrollbar, can't do this test");
     return;
   }
 
   // the events above might be stuck in APZ input queue for a bit until the
   // layer is activated, so we wait here until the scroll event listener is
   // triggered.
   yield;
 
+  yield* dragFinisher();
+
   // Flush everything just to be safe
   yield flushApzRepaints(testDriver);
 
   // After dragging the scrollbar 20px on a 200px-high scrollable div, we should
   // have scrolled approx 10% of the 2000px high content. There might have been
   // scroll arrows and such so let's just have a minimum bound of 50px to be safe.
   ok(scrollableDiv.scrollTop > 50, "Scrollbar drag resulted in a scroll position of " + scrollableDiv.scrollTop);
 }
--- a/gfx/layers/apz/test/mochitest/helper_bug1346632.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1346632.html
@@ -20,57 +20,40 @@
       z-index: 1000;
       overflow-y: scroll;
     }
     #fixed-content {
       height: 2000px;
     }
   </style>
   <script type="text/javascript">
-var root;
-var scrollPos;
-var haveScrolled = false;
-var generatedAll = false;
-
-// Be careful not to call subtestDone() until we've scrolled AND generated
-// all of the events.
-function maybeDone() {
-  if (haveScrolled && generatedAll) {
-    subtestDone();
-  }
-}
-
-function scrolled(e) {
-  // Test that we have scrolled
-  ok(root.scrollTop > scrollPos, "document scrolled after dragging scrollbar");
-  haveScrolled = true;
-  maybeDone();
-}
-
 function* test(testDriver) {
-  root = document.scrollingElement;
-  scrollPos = root.scrollTop;
-  document.addEventListener('scroll', scrolled);
+  var root = document.scrollingElement;
+  var scrollPos = root.scrollTop;
+  document.addEventListener('scroll', () => {
+    ok(root.scrollTop > scrollPos, "document scrolled after dragging scrollbar");
+    setTimeout(testDriver, 0);
+  }, {once: true});
 
   var scrollbarX = (window.innerWidth + root.clientWidth) / 2;
   // Move the mouse to the scrollbar
   yield synthesizeNativeMouseEvent(root, scrollbarX, 100, nativeMouseMoveEventMsg(), testDriver);
   // mouse down
   yield synthesizeNativeMouseEvent(root, scrollbarX, 100, nativeMouseDownEventMsg(), testDriver);
   // drag vertically
   yield synthesizeNativeMouseEvent(root, scrollbarX, 150, nativeMouseMoveEventMsg(), testDriver);
+  // wait for the scroll listener to fire, which will resume this function
+  yield;
   // and release
   yield synthesizeNativeMouseEvent(root, scrollbarX, 150, nativeMouseUpEventMsg(), testDriver);
-
-  generatedAll = true;
-  maybeDone();
 }
 
 waitUntilApzStable()
-.then(runContinuation(test));
+.then(runContinuation(test))
+.then(subtestDone);
 
   </script>
 </head>
 <body>
   <div id="fixed">
     <p id="fixed-content"></p>
   </div>
 </body>
--- a/gfx/layers/apz/test/mochitest/helper_bug1462961.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1462961.html
@@ -12,27 +12,29 @@
 function* test(testDriver) {
   var scrollableDiv = document.getElementById('scrollable');
   scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
 
   // Scroll down a small amount (10px). The bug in this case is that the
   // scrollthumb remains a little "above" where it's supposed to be, so if the
   // bug manifests here, then the thumb will remain at the top of the track
   // and the scroll position will remain at 0.
-  var scrolled = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
-  if (!scrolled) {
+  var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
+  if (!dragFinisher) {
     ok(true, "No scrollbar, can't do this test");
     return;
   }
 
   // the events above might be stuck in APZ input queue for a bit until the
   // layer is activated, so we wait here until the scroll event listener is
   // triggered.
   yield;
 
+  yield* dragFinisher();
+
   // Flush everything just to be safe
   yield flushApzRepaints(testDriver);
 
   // In this case we just want to make sure the scroll position moved from 0
   // which indicates the thumb dragging worked properly.
   ok(scrollableDiv.scrollTop > 0, "Scrollbar drag resulted in a scroll position of " + scrollableDiv.scrollTop);
 }