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
--- 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) };