Bug 972110 Rewrite editor/libeditor/test_bug674770-1.html without setTimeout() for avoiding intermittent failure r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 21 Sep 2016 21:27:52 +0900
changeset 416144 a00b928e813e92086db22c4beac846f50561dc46
parent 415495 62f79d676e0e11b3ad59a5425b3ebb3ec5bbefb5
child 531763 a7519452828f8b467cfdc4e4e6737f27396a07f9
push id30040
push usermasayuki@d-toybox.com
push dateWed, 21 Sep 2016 15:10:34 +0000
reviewerssmaug
bugs972110, 674770
milestone52.0a1
Bug 972110 Rewrite editor/libeditor/test_bug674770-1.html without setTimeout() for avoiding intermittent failure r?smaug We can assume that if middle button's click event on a link isn't consumed by any event handlers including system event group's, it will cause open new tab. With this assumption, we can avoid using setTimeout which causes random orange. However, unfortunately, in e10s mode, the default is NOT consumed at window in bubbling phase but consumed at that time. So, when not working the link is expected, we cannot check Event.defaultPrevented. But fortunately, we can check if the page is loaded after that. Note that for testing this, the test needs to check if an event handler which is either in default group or system group consumed a click event. However, this runs as mochitest-plain. Therefore, Event.defaultPrevented returns false if the event is consumed only in the system group's event listener. For avoiding this issue, this patch adds defaultPreventedInAnyGroups() into SpecialPowers. In SpecialPowers, Event.defaultPrevented is accessed from chrome context. Therefore, we can get the result what this test needs. MozReview-Commit-ID: Cfn4lFR1dfI
editor/libeditor/tests/mochitest.ini
editor/libeditor/tests/test_bug674770-1.html
testing/specialpowers/content/specialpowersAPI.js
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -114,17 +114,17 @@ skip-if = toolkit == 'android' #bug 9577
 [test_bug638596.html]
 [test_bug640321.html]
 skip-if = android_version == '18' # bug 1147989
 [test_bug641466.html]
 [test_bug645914.html]
 [test_bug668599.html]
 [test_bug674770-1.html]
 subsuite = clipboard
-skip-if = toolkit == 'android' || (os == 'linux' && e10s && (debug||asan)) # Bug 972110
+skip-if = toolkit == 'android'
 [test_bug674770-2.html]
 subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug674861.html]
 [test_bug676401.html]
 [test_bug677752.html]
 [test_bug681229.html]
 subsuite = clipboard
--- a/editor/libeditor/tests/test_bug674770-1.html
+++ b/editor/libeditor/tests/test_bug674770-1.html
@@ -19,51 +19,62 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a href="file_bug674770-1.html" id="link2">test</a>
 </div>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
-  SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true]]}, startTest);
+  SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true]]}, startTests);
 });
-function startTest() {
-  localStorage.removeItem("clicked");
-  window.linkWasClicked = false;
 
-  var link = document.querySelector("#link1");
-  addEventListener("storage", function(e) {
-    is(e.key, "clicked", "Correct event");
-    is(e.newValue, "true", "Correct value");
-    window.linkWasClicked = true;
-  }, false);
-  synthesizeMouseAtCenter(link, {button: 1});
-
-  hitEventLoop(function() {
-    ok(window.linkWasClicked, "The click operation worked successfully");
-    window.linkWasClicked = false;
+function startTests() {
+  var tests = [
+    { description: "Testing link in <div>: ",
+      target: function () { return document.querySelector("#link1"); },
+      linkShouldWork: true },
+    { description: "Testing link in <div contenteditable>: ",
+      target: function () { return document.querySelector("#link2"); },
+      linkShouldWork: false },
+  ];
+  var currentTest;
+  function runNextTest() {
+    localStorage.removeItem("clicked");
+    currentTest = tests.shift();
+    if (!currentTest) {
+      SimpleTest.finish();
+      return;
+    }
+    ok(true, currentTest.description + "Starting to test...");
+    synthesizeMouseAtCenter(currentTest.target(), { button: 1 });
+  }
 
-    link = document.querySelector("#link2");
-    localStorage.removeItem("clicked");
-    synthesizeMouseAtCenter(link, {button: 1});
-
-    hitEventLoop(function() {
-      ok(!window.linkWasClicked, "The click operation shouldn't work in the contenteditable area");
+  addEventListener("storage", function(e) {
+    is(e.key, "clicked", currentTest.description + "Key should always be 'clicked'");
+    is(e.newValue, "true", currentTest.description + "Value should always be 'true'");
+    ok(currentTest.linkShouldWork, currentTest.description + "The click operation on the link " + (currentTest.linkShouldWork ? "should work" : "shouldn't work"));
+    // Note that in e10s mode, click event will be fired after this event.
+    SimpleTest.executeSoon(runNextTest);
+  }, false);
 
-      localStorage.removeItem("clicked");
-      SimpleTest.finish();
-    }, 100);
-  }, 100);
-}
+  SpecialPowers.addSystemEventListener(window, "click", function (aEvent) {
+    // If the click event should cause default action, e.g., opening the link, it shouldn't have been consumed by the editor in e10s mode.
+    // However, in e10s mode, it's been already consumed, so, we shouldn't check defaultPrevented value when the link should work as is.
+    if (currentTest.linkShouldWork) {
+      return;
+    }
 
-function hitEventLoop(func, times) {
-  if (times > 0) {
-    setTimeout(hitEventLoop, 0, func, times - 1);
-  } else {
-    setTimeout(func, 0);
-  }
+    ok(SpecialPowers.defaultPreventedInAnyGroups(aEvent),
+       currentTest.description + "The default action should be consumed because the link should work as is");
+    if (SpecialPowers.defaultPreventedInAnyGroups(aEvent)) {
+      // In this case, "storage" event won't be fired.
+      SimpleTest.executeSoon(runNextTest);
+    }
+  }, false);
+
+  SimpleTest.executeSoon(runNextTest);
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1590,16 +1590,24 @@ SpecialPowersAPI.prototype = {
       addSystemEventListener(target, type, listener, useCapture);
   },
   removeSystemEventListener: function(target, type, listener, useCapture) {
     Cc["@mozilla.org/eventlistenerservice;1"].
       getService(Ci.nsIEventListenerService).
       removeSystemEventListener(target, type, listener, useCapture);
   },
 
+  // helper method to check if the event is consumed by either default group's
+  // event listener or system group's event listener.
+  defaultPreventedInAnyGroups: function(event) {
+    // FYI: Event.defaultPrevented returns false in content context if the
+    //      event is consumed only by system group's event listeners.
+    return event.defaultPrevented;
+  },
+
   getDOMRequestService: function() {
     var serv = Services.DOMRequest;
     var res = {};
     var props = ["createRequest", "createCursor", "fireError", "fireSuccess",
                  "fireDone", "fireDetailedError"];
     for (var i in props) {
       let prop = props[i];
       res[prop] = function() { return serv[prop].apply(serv, arguments) };