Bug 1271819 - Rewrite browser_focus_steal_from_chrome to avoid race condition. r=enndeakin, a=test-only
authorMichael Layzell <michael@thelayzells.com>
Fri, 29 Jul 2016 17:14:55 -0400
changeset 349754 155c58e4fe0e214a7f8930d9d7d7b93eef91d763
parent 349753 8806d8bbf1e16d1865678a32dfb948f28d761617
child 349755 a9491e79c1aebebd47be6113f7f577df4c9de198
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenndeakin, test-only
bugs1271819
milestone50.0a2
Bug 1271819 - Rewrite browser_focus_steal_from_chrome to avoid race condition. r=enndeakin, a=test-only
dom/tests/browser/browser_focus_steal_from_chrome.js
--- a/dom/tests/browser/browser_focus_steal_from_chrome.js
+++ b/dom/tests/browser/browser_focus_steal_from_chrome.js
@@ -1,20 +1,10 @@
-function test() {
-  waitForExplicitFinish();
-
-  let secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
-                         .getService(Components.interfaces
-                                               .nsIScriptSecurityManager);
-
-  let fm = Components.classes["@mozilla.org/focus-manager;1"]
-                     .getService(Components.interfaces.nsIFocusManager);
-
-  let tabs = [ gBrowser.addTab(), gBrowser.addTab() ];
-  gBrowser.selectedTab = tabs[0];
+add_task(function* () {
+  requestLongerTimeout(2);
 
   let testingList = [
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><input id='target'></body>",
       tagName: "INPUT", methodName: "focus" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').select(); }, 10);\"><input id='target'></body>",
       tagName: "INPUT", methodName: "select" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><a href='about:blank' id='target'>anchor</a></body>",
       tagName: "A", methodName: "focus" },
@@ -26,189 +16,149 @@ function test() {
       tagName: "TEXTAREA", methodName: "focus" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').select(); }, 10);\"><textarea id='target'>textarea</textarea></body>",
       tagName: "TEXTAREA", methodName: "select" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><label id='target'><input></label></body>",
       tagName: "INPUT", methodName: "focus of label element" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><fieldset><legend id='target'>legend</legend><input></fieldset></body>",
       tagName: "INPUT", methodName: "focus of legend element" },
     { uri: "data:text/html,<body onload=\"setTimeout(function () {" +
-           "  var element = document.getElementById('target');" +
-           "  var event = document.createEvent('MouseEvent');" +
-           "  event.initMouseEvent('click', true, true, window," +
-           "    1, 0, 0, 0, 0, false, false, false, false, 0, element);" +
-           "  element.dispatchEvent(event); }, 10);\">" +
-           "<label id='target'><input></label></body>",
+      "  var element = document.getElementById('target');" +
+      "  var event = document.createEvent('MouseEvent');" +
+      "  event.initMouseEvent('click', true, true, window," +
+      "    1, 0, 0, 0, 0, false, false, false, false, 0, element);" +
+      "  element.dispatchEvent(event); }, 10);\">" +
+      "<label id='target'><input></label></body>",
       tagName: "INPUT", methodName: "click event on the label element" },
   ];
 
   if (navigator.platform.indexOf("Mac") == -1) {
     // clicking buttons doesn't focus on mac, so skip this test
     testingList.push(
       { uri: "data:text/html,<body onload=\"setTimeout(function () {" +
-             "  var element = document.getElementById('target');" +
-             "  var event = document.createEvent('MouseEvent');" +
-             "  event.initMouseEvent('mousedown', true, true, window," +
-             "    0, 0, 0, 0, 0, false, false, false, false, 0, element);" +
-             "  element.dispatchEvent(event); }, 10);\">" +
-             "<button id='target'>button</button></body>",
+        "  var element = document.getElementById('target');" +
+        "  var event = document.createEvent('MouseEvent');" +
+        "  event.initMouseEvent('mousedown', true, true, window," +
+        "    0, 0, 0, 0, 0, false, false, false, false, 0, element);" +
+        "  element.dispatchEvent(event); }, 10);\">" +
+        "<button id='target'>button</button></body>",
         tagName: "BUTTON", methodName: "mousedown event on the button element" });
   }
 
-  let testingIndex = -1;
-  let canRetry;
-  let callback;
-  let loadedCount;
-  let setFocusToChrome;
+  yield BrowserTestUtils.withNewTab("about:blank", function*(bg) {
+    yield BrowserTestUtils.withNewTab("about:blank", function*(fg) {
+      for (let test of testingList) {
+        // Focus the foreground tab's content
+        fg.focus();
 
-  function runNextTest() {
-    if (++testingIndex >= testingList.length) {
-      // cleaning-up...
-      for (let i = 0; i < tabs.length; i++) {
-        gBrowser.removeTab(tabs[i]);
-      }
-      finish();
-      return;
-    }
-    callback = doTest1;
-    loadTestPage(false);
-  }
+        // Load the URIs.
+        yield BrowserTestUtils.loadURI(bg, test.uri);
+        yield BrowserTestUtils.browserLoaded(bg);
+        yield BrowserTestUtils.loadURI(fg, test.uri);
+        yield BrowserTestUtils.browserLoaded(fg);
 
-  function loadTestPage(aSetFocusToChrome) {
-    loadedCount = 0;
-    canRetry = 10;
-    setFocusToChrome = aSetFocusToChrome;
-    // Set the focus to the contents.
-    tabs[0].linkedBrowser.focus();
-    // Load on the tabs
-    tabs[0].linkedBrowser.addEventListener("load", onLoadForegroundTab, true);
-    tabs[0].linkedBrowser.loadURI(testingList[testingIndex].uri);
-    tabs[1].linkedBrowser.addEventListener("load", onLoadBackgroundTab, true);
-    tabs[1].linkedBrowser.loadURI(testingList[testingIndex].uri);
-  }
+        ok(true, "Test1: Both of the tabs are loaded");
 
-  function onLoadForegroundTab() {
-    tabs[0].linkedBrowser.removeEventListener("load", onLoadForegroundTab, true);
-    if (setFocusToChrome) {
-      // Set focus to a chrome element before the loaded content tries to move
-      // focus.
-      document.getElementById("urlbar").focus();
-    }
-    onLoadComplete();
-  }
-
-  function onLoadBackgroundTab() {
-    tabs[1].linkedBrowser.removeEventListener("load", onLoadBackgroundTab, true);
-    onLoadComplete();
-  }
+        // Confirm that the contents should be able to steal focus from content.
+        yield ContentTask.spawn(fg, test, test => {
+          return new Promise(res => {
+            function f() {
+              let e = content.document.activeElement;
+              if (e.tagName != test.tagName) {
+                setTimeout(f, 10);
+              } else {
+                is(Services.focus.focusedElement, e,
+                   "the foreground tab's " + test.tagName +
+                   " element isn't focused by the " + test.methodName +
+                   " (Test1: content can steal focus)");
+                res();
+              }
+            }
+            f();
+          });
+        });
 
-  function onLoadComplete() {
-    if (++loadedCount == tabs.length) {
-      setTimeout(callback, 20);
-    }
-  }
+        yield ContentTask.spawn(bg, test, test => {
+          return new Promise(res => {
+            function f() {
+              let e = content.document.activeElement;
+              if (e.tagName != test.tagName) {
+                setTimeout(f, 10);
+              } else {
+                isnot(Services.focus.focusedElement, e,
+                      "the background tab's " + test.tagName +
+                      " element is focused by the " + test.methodName +
+                      " (Test1: content can steal focus)");
+                res();
+              }
+            }
+            f();
+          });
+        });
 
-  function isPrepared() {
-    for (let i = 0; i < tabs.length; i++) {
-      if (tabs[i].linkedBrowser.contentDocument.activeElement.tagName !=
-            testingList[testingIndex].tagName) {
-        return false;
-      }
-    }
-    return true;
-  }
+        if (fg.isRemoteBrowser) {
+          is(Services.focus.focusedElement, fg,
+             "Focus should be on the content in the parent process");
+        }
 
-  function doTest1() {
-    if (canRetry-- > 0 && !isPrepared()) {
-      setTimeout(callback, 10); // retry
-      return;
-    }
-
-    // The contents should be able to steal the focus from content.
+        // Focus chrome
+        document.getElementById("urlbar").focus();
+        let originalFocus = Services.focus.focusedElement;
 
-    // in foreground tab
-    ContentTask.spawn(tabs[0].linkedBrowser, null, function (opts) {
-      let fm = Components.classes["@mozilla.org/focus-manager;1"]
-            .getService(Components.interfaces.nsIFocusManager);
-      let e = content.document.activeElement;
-      return [e.tagName, fm.focusedElement == e];
-    }).then(result => {
-      is(result[0], testingList[testingIndex].tagName,
-         "the foreground tab's " + testingList[testingIndex].tagName +
-         " element is not active by the " + testingList[testingIndex].methodName +
-         " (Test1: content can steal focus)");
-      ok(result[1],
-         "the " + testingList[testingIndex].tagName +
-         " element isn't focused by the " + testingList[testingIndex].methodName +
-         " (Test1: content can steal focus)");
+        // Load about:blank just to make sure that everything works nicely
+        yield BrowserTestUtils.loadURI(bg, "about:blank");
+        yield BrowserTestUtils.browserLoaded(bg);
+        yield BrowserTestUtils.loadURI(fg, "about:blank");
+        yield BrowserTestUtils.browserLoaded(fg);
 
-      // in background tab
-    }).then(() => ContentTask.spawn(tabs[1].linkedBrowser, null, function (opts) {
-      let fm = Components.classes["@mozilla.org/focus-manager;1"]
-            .getService(Components.interfaces.nsIFocusManager);
-      let e = content.document.activeElement;
-      return [e.tagName, fm.focusedElement == e];
-    })).then(result => {
-      is(result[0], testingList[testingIndex].tagName,
-         "the background tab's " + testingList[testingIndex].tagName +
-         " element is not active by the " + testingList[testingIndex].methodName +
-         " (Test1: content can steal focus)");
-      ok(!result[1],
-         "the " + testingList[testingIndex].tagName +
-         " element is focused by the " + testingList[testingIndex].methodName +
-         " (Test1: content can steal focus)");
-    }).then(() => {
-      callback = doTest2;
-      loadTestPage(true);
-    }).catch(err => {
-      ok(false, "Error: " + err);
-    });
-  }
+        // Load the URIs.
+        yield BrowserTestUtils.loadURI(bg, test.uri);
+        yield BrowserTestUtils.browserLoaded(bg);
+        yield BrowserTestUtils.loadURI(fg, test.uri);
+        yield BrowserTestUtils.browserLoaded(fg);
 
+        ok(true, "Test2: Both of the tabs are loaded");
 
-  function doTest2() {
-    if (canRetry-- > 0 && !isPrepared()) {
-      setTimeout(callback, 10); // retry
-      return;
-    }
-
-    // The contents shouldn't be able to steal the focus from content.
-
-    // in foreground tab
-    ContentTask.spawn(tabs[0].linkedBrowser, null, function (opts) {
-      let fm = Components.classes["@mozilla.org/focus-manager;1"]
-            .getService(Components.interfaces.nsIFocusManager);
-      let e = content.document.activeElement;
-      return [e.tagName, fm.focusedElement == e];
-    }).then(result => {
-      is(result[0], testingList[testingIndex].tagName,
-         "the foreground tab's " + testingList[testingIndex].tagName +
-         " element is not active by the " + testingList[testingIndex].methodName +
-         " (Test2: content can NOT steal focus)");
-      ok(!result[1],
-         "the " + testingList[testingIndex].tagName +
-         " element is focused by the " + testingList[testingIndex].methodName +
-         " (Test2: content can NOT steal focus)");
+        // Confirm that the contents should be able to steal focus from content.
+        yield ContentTask.spawn(fg, test, test => {
+          return new Promise(res => {
+            function f() {
+              let e = content.document.activeElement;
+              if (e.tagName != test.tagName) {
+                setTimeout(f, 10);
+              } else {
+                isnot(Services.focus.focusedElement, e,
+                      "the foreground tab's " + test.tagName +
+                      " element is focused by the " + test.methodName +
+                      " (Test2: content can NOT steal focus)");
+                res();
+              }
+            }
+            f();
+          });
+        });
 
-      // in background tab
-    }).then(() => ContentTask.spawn(tabs[1].linkedBrowser, null, function (opts) {
-      let fm = Components.classes["@mozilla.org/focus-manager;1"]
-            .getService(Components.interfaces.nsIFocusManager);
-      let e = content.document.activeElement;
-      return [e.tagName, fm.focusedElement == e];
-    })).then(result => {
-      is(result[0], testingList[testingIndex].tagName,
-         "the background tab's " + testingList[testingIndex].tagName +
-         " element is not active by the " + testingList[testingIndex].methodName +
-         " (Test2: content can NOT steal focus)");
-      ok(!result[1],
-         "the " + testingList[testingIndex].tagName +
-         " element is focused by the " + testingList[testingIndex].methodName +
-         " (Test2: content can NOT steal focus)");
-    }).then(() => {
-      runNextTest();
-    }).catch(err => {
-      ok(false, "Error: " + err);
+        yield ContentTask.spawn(bg, test, test => {
+          return new Promise(res => {
+            function f() {
+              let e = content.document.activeElement;
+              if (e.tagName != test.tagName) {
+                setTimeout(f, 10);
+              } else {
+                isnot(Services.focus.focusedElement, e,
+                      "the background tab's " + test.tagName +
+                      " element is focused by the " + test.methodName +
+                      " (Test2: content can NOT steal focus)");
+                res();
+              }
+            }
+            f();
+          });
+        });
+
+        is(Services.focus.focusedElement, originalFocus,
+           "The parent process's focus has shifted " +
+           "(methodName = " + test.methodName + ")" +
+           " (Test2: content can NOT steal focus)");
+      }
     });
-  }
-
-  runNextTest();
-}
+  });
+});