Bug 1262946 - Add focus tests for newly opened windows. r?Gijs
MozReview-Commit-ID: 2353D0oA0yO
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -573,8 +573,10 @@ skip-if = !e10s || !crashreporter
[browser_aboutTabCrashed_clearEmail.js]
skip-if = !e10s || !crashreporter
[browser_aboutTabCrashed_showForm.js]
skip-if = !e10s || !crashreporter
[browser_aboutTabCrashed_withoutDump.js]
skip-if = !e10s
[browser_csp_block_all_mixedcontent.js]
tags = mcb
+[browser_newwindow_focus.js]
+skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_newwindow_focus.js
@@ -0,0 +1,96 @@
+"use strict";
+
+/**
+ * These tests are for the auto-focus behaviour on the initial browser
+ * when a window is opened from content.
+ */
+
+const PAGE = `data:text/html,<a id="target" href="%23" onclick="window.open('http://www.example.com', '_blank', 'width=100,height=100');">Click me</a>`;
+
+/**
+ * Returns a Promise that resolves when a new window has
+ * opened, and the "load" event has fired in that window.
+ * We can't use BrowserTestUtils.domWindowOpened directly,
+ * because by the time the "then" on the Promise runs,
+ * DOMContentLoaded and load may have already run in the new
+ * window. However, we want to be very explicit about what
+ * events we're waiting for, and not rely on a quirk of our
+ * Promises infrastructure.
+ */
+function promiseNewWindow() {
+ return new Promise((resolve) => {
+ let observer = (subject, topic, data) => {
+ if (topic == "domwindowopened") {
+ Services.ww.unregisterNotification(observer);
+ let win = subject.QueryInterface(Ci.nsIDOMWindow);
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve(win);
+ });
+ }
+ };
+
+ Services.ww.registerNotification(observer);
+ });
+}
+
+/**
+ * Test that when a new window is opened from content, focus moves
+ * to the initial browser in that window once the window has finished
+ * painting.
+ */
+add_task(function* test_focus_browser() {
+ yield BrowserTestUtils.withNewTab({
+ url: PAGE,
+ gBrowser,
+ }, function*(browser) {
+ let newWinPromise = promiseNewWindow();
+ let delayedStartupPromise = BrowserTestUtils.waitForNewWindow();
+
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#target", {}, browser);
+ let newWin = yield newWinPromise;
+ yield BrowserTestUtils.contentPainted(newWin.gBrowser.selectedBrowser);
+ yield delayedStartupPromise;
+
+ let focusedElement =
+ Services.focus.getFocusedElementForWindow(newWin, false, {});
+
+ Assert.equal(focusedElement, newWin.gBrowser.selectedBrowser,
+ "Initial browser should be focused");
+
+ yield BrowserTestUtils.closeWindow(newWin);
+ });
+});
+
+/**
+ * Test that when a new window is opened from content and focus
+ * shifts in that window before the content has a chance to paint
+ * that we _don't_ steal focus once content has painted.
+ */
+add_task(function* test_no_steal_focus() {
+ yield BrowserTestUtils.withNewTab({
+ url: PAGE,
+ gBrowser,
+ }, function*(browser) {
+ let newWinPromise = promiseNewWindow();
+ let delayedStartupPromise = BrowserTestUtils.waitForNewWindow();
+
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#target", {}, browser);
+ let newWin = yield newWinPromise;
+
+ // Because we're switching focus, we shouldn't steal it once
+ // content paints.
+ newWin.gURLBar.focus();
+
+ yield BrowserTestUtils.contentPainted(newWin.gBrowser.selectedBrowser);
+ yield delayedStartupPromise;
+
+ let focusedElement =
+ Services.focus.getFocusedElementForWindow(newWin, false, {});
+
+ Assert.equal(focusedElement, newWin.gURLBar.inputField,
+ "URLBar should be focused");
+
+ yield BrowserTestUtils.closeWindow(newWin);
+ });
+});
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -1040,9 +1040,29 @@ this.BrowserTestUtils = {
BrowserTestUtils.waitForEvent(notificationBox, "AlertActive",
false, check).then((event) => {
// The originalTarget of the AlertActive on a notificationbox
// will be the notification itself.
resolve(event.originalTarget);
});
});
},
+
+ /**
+ * Returns a Promise that will resolve once MozAfterPaint
+ * has been fired in the content of a browser.
+ *
+ * @param browser (<xul:browser>)
+ * The browser for which we're waiting for the MozAfterPaint
+ * event to occur in.
+ * @returns Promise
+ */
+ contentPainted(browser) {
+ return ContentTask.spawn(browser, null, function*() {
+ return new Promise((resolve) => {
+ addEventListener("MozAfterPaint", function onPaint() {
+ removeEventListener("MozAfterPaint", onPaint);
+ resolve();
+ })
+ });
+ });
+ },
};