Bug 972110 - Rewrite editor/libeditor/test_bug674770-1.html without setTimeout() for avoiding intermittent failure. r=smaug, a=test-only
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 22 Sep 2016 10:54:51 +0900
changeset 355708 13ed0212fab765bad762a64b412a5ee4ccbf1f2a
parent 355707 792b8ce232c626626c5246da4277726731e93480
child 355709 061867df5aabf908aa3d444d2b9a7527fe4d9195
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, test-only
bugs972110, 674770
milestone51.0a2
Bug 972110 - Rewrite editor/libeditor/test_bug674770-1.html without setTimeout() for avoiding intermittent failure. r=smaug, a=test-only 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,67 @@ 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"));
+    SimpleTest.executeSoon(runNextTest);
+  }, false);
 
-      localStorage.removeItem("clicked");
-      SimpleTest.finish();
-    }, 100);
-  }, 100);
-}
+  SpecialPowers.addSystemEventListener(window, "click", function (aEvent) {
+    // When the click event should cause default action, e.g., opening the link,
+    // the event shouldn't have been consumed except the link handler.
+    // However, in e10s mode, it's not consumed during propagating the event but
+    // in non-e10s mode, it's consumed during the propagation.  Therefore,
+    // we cannot check defaultPrevented value when the link should work as is
+    // if there is no way to detect if it's running in e10s mode or not.
+    // So, let's skip checking Event.defaultPrevented value when the link should
+    // work.  In such case, we should receive "storage" event later.
+    if (currentTest.linkShouldWork) {
+      return;
+    }
 
-function hitEventLoop(func, times) {
-  if (times > 0) {
-    setTimeout(hitEventLoop, 0, func, times - 1);
-  } else {
-    setTimeout(func, 0);
-  }
+    ok(SpecialPowers.defaultPreventedInAnyGroup(aEvent),
+       currentTest.description + "The default action should be consumed because the link should work as is");
+    if (SpecialPowers.defaultPreventedInAnyGroup(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.
+  defaultPreventedInAnyGroup: 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) };