Bug 1432856 - Added tests for window open and focus in fullscreen. r=smaug
authorpbz <pbz@mozilla.com>
Thu, 16 Jan 2020 14:39:11 +0000
changeset 510492 03b7899094663bba35802764ac8f15d9f28f69da
parent 510491 7594dab35ba4fcb5ce33e58cfae265aa76787f8d
child 510493 a03b869d45a9680b63d45d96f217c2c476b20d09
push id105313
push userpzuhlcke@mozilla.com
push dateThu, 16 Jan 2020 15:09:28 +0000
treeherderautoland@a03b869d45a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1432856
milestone74.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1432856 - Added tests for window open and focus in fullscreen. r=smaug Differential Revision: https://phabricator.services.mozilla.com/D56391
browser/base/content/test/fullscreen/browser.ini
browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js
browser/base/content/test/fullscreen/browser_fullscreen_window_open.js
browser/base/content/test/fullscreen/head.js
browser/base/content/test/fullscreen/open_and_focus_helper.html
--- a/browser/base/content/test/fullscreen/browser.ini
+++ b/browser/base/content/test/fullscreen/browser.ini
@@ -1,9 +1,14 @@
 [DEFAULT]
 support-files =
   head.js
+  open_and_focus_helper.html
 [browser_bug1557041.js]
 skip-if = os == 'linux' # Bug 1561973
 [browser_fullscreen_permissions_prompt.js]
 skip-if = debug && os == 'mac' # Bug 1568570
 [browser_fullscreen_cross_origin.js]
 support-files = fullscreen.html fullscreen_frame.html
+[browser_fullscreen_window_open.js]
+skip-if = debug && os == 'mac' # Bug 1568570
+[browser_fullscreen_window_focus.js]
+skip-if = debug && os == 'mac' # Bug 1568570
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/fullscreen/browser_fullscreen_window_focus.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+const TEST_URL =
+  "http://example.com/browser/browser/base/content/test/fullscreen/open_and_focus_helper.html";
+const IFRAME_ID = "testIframe";
+
+async function testWindowFocus(iframeID) {
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+  info("Calling window.open()");
+  let popup = await jsWindowOpen(tab.linkedBrowser, iframeID);
+  info("re-focusing main window");
+  await waitForFocus();
+
+  info("Entering full-screen");
+  await changeFullscreen(tab.linkedBrowser, true);
+
+  await testExpectFullScreenExit(tab.linkedBrowser, true, async () => {
+    info("Calling window.focus()");
+    await jsWindowFocus(tab.linkedBrowser, iframeID);
+  });
+
+  // Cleanup
+  popup.close();
+  BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["dom.disable_open_during_load", false], // Allow window.focus calls without user interaction
+      ["browser.link.open_newwindow.disabled_in_fullscreen", false],
+    ],
+  });
+});
+
+add_task(function test_parentWindowFocus() {
+  return testWindowFocus();
+});
+
+add_task(function test_iframeWindowFocus() {
+  return testWindowFocus(IFRAME_ID);
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/fullscreen/browser_fullscreen_window_open.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+SimpleTest.requestLongerTimeout(2);
+
+const TEST_URL =
+  "http://example.com/browser/browser/base/content/test/fullscreen/open_and_focus_helper.html";
+const IFRAME_ID = "testIframe";
+
+async function testWindowOpen(iframeID) {
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+  info("Entering full-screen");
+  await changeFullscreen(tab.linkedBrowser, true);
+
+  let popup;
+  await testExpectFullScreenExit(tab.linkedBrowser, true, async () => {
+    info("Calling window.open()");
+    popup = await jsWindowOpen(tab.linkedBrowser, iframeID);
+  });
+
+  // Cleanup
+  await BrowserTestUtils.closeWindow(popup);
+  BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["dom.disable_open_during_load", false], // Allow window.open calls without user interaction
+      ["browser.link.open_newwindow.disabled_in_fullscreen", false],
+    ],
+  });
+});
+
+add_task(function test_parentWindowOpen() {
+  return testWindowOpen();
+});
+
+add_task(function test_iframeWindowOpen() {
+  return testWindowOpen(IFRAME_ID);
+});
--- a/browser/base/content/test/fullscreen/head.js
+++ b/browser/base/content/test/fullscreen/head.js
@@ -1,26 +1,25 @@
 const { ContentTaskUtils } = ChromeUtils.import(
   "resource://testing-common/ContentTaskUtils.jsm"
 );
 function waitForFullScreenState(browser, state) {
-  info("inside waitforfullscreenstate");
   return new Promise(resolve => {
     let eventReceived = false;
 
     let observe = (subject, topic, data) => {
       if (!eventReceived) {
         return;
       }
       Services.obs.removeObserver(observe, "fullscreen-painted");
       resolve();
     };
     Services.obs.addObserver(observe, "fullscreen-painted");
 
-    window.addEventListener(
+    browser.ownerGlobal.addEventListener(
       `MozDOMFullscreen:${state ? "Entered" : "Exited"}`,
       () => {
         eventReceived = true;
       },
       { once: true }
     );
   });
 }
@@ -45,8 +44,83 @@ async function changeFullscreen(browser,
     if (state) {
       content.document.body.requestFullscreen();
     } else {
       content.document.exitFullscreen();
     }
   });
   return fullScreenChange;
 }
+
+async function testExpectFullScreenExit(browser, leaveFS, action) {
+  let fsPromise = waitForFullScreenState(browser, !leaveFS);
+  if (leaveFS) {
+    if (action) {
+      await action();
+    }
+    await fsPromise;
+    ok(true, "Should leave full-screen");
+  } else {
+    if (action) {
+      await action();
+    }
+    let result = await Promise.race([
+      fsPromise,
+      new Promise(resolve => {
+        SimpleTest.requestFlakyTimeout("Wait for failure condition");
+        // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+        setTimeout(() => resolve(true), 2500);
+      }),
+    ]);
+    ok(result, "Should not leave full-screen");
+  }
+}
+
+function jsWindowFocus(browser, iframeId) {
+  return ContentTask.spawn(browser, { iframeId }, async args => {
+    let destWin = content;
+    if (args.iframeId) {
+      let iframe = content.document.getElementById(args.iframeId);
+      if (!iframe) {
+        throw new Error("iframe not set");
+      }
+      destWin = iframe.contentWindow;
+    }
+    await content.wrappedJSObject.sendMessage(destWin, "focus");
+  });
+}
+
+async function jsWindowOpen(browser, iframeId) {
+  let windowOpened = BrowserTestUtils.waitForNewWindow();
+  ContentTask.spawn(browser, { iframeId }, async args => {
+    let destWin = content;
+    if (args.iframeId) {
+      // Create a cross origin iframe
+      destWin = (await content.wrappedJSObject.createIframe(
+        args.iframeId,
+        true
+      )).contentWindow;
+    }
+    // Send message to either the iframe or the current page to open a popup
+    await content.wrappedJSObject.sendMessage(destWin, "open");
+  });
+  return windowOpened;
+}
+
+function waitForFocus(...args) {
+  return new Promise(resolve => SimpleTest.waitForFocus(resolve, ...args));
+}
+
+function waitForBrowserWindowActive(win) {
+  return new Promise(resolve => {
+    if (Services.focus.activeWindow == win) {
+      resolve();
+    } else {
+      win.addEventListener(
+        "activate",
+        () => {
+          resolve();
+        },
+        { once: true }
+      );
+    }
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/fullscreen/open_and_focus_helper.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset='utf-8'>
+</head>
+<body>
+  <script>
+    const MY_ORIGIN = window.location.origin;
+    const CROSS_ORIGIN = "https://example.org";
+
+    // Creates an iframe with message channel to trigger window open and focus
+    window.createIframe = function(id, crossOrigin = false) {
+      return new Promise(resolve => {
+        const origin = crossOrigin ? CROSS_ORIGIN : MY_ORIGIN;
+        let iframe = document.createElement("iframe");
+        iframe.id = id;
+        iframe.src = origin + window.location.pathname;
+        iframe.onload = () => resolve(iframe);
+        document.body.appendChild(iframe);
+      });
+    }
+
+    window.sendMessage = function(destWin, msg) {
+      return new Promise(resolve => {
+        let channel = new MessageChannel();
+        channel.port1.onmessage = resolve;
+        destWin.postMessage(msg, "*", [channel.port2]);
+      });
+    }
+
+    window.onMessage = function(event) {
+      let canReply = event.ports && !!event.ports.length;
+      if(event.data === "open") {
+        window.popup = window.open('https://example.com', '', 'top=0,height=1, width=300');
+        if (canReply) event.ports[0].postMessage('opened');
+      } else if(event.data === "focus") {
+        window.popup.focus();
+        if (canReply) event.ports[0].postMessage('focused');
+      }
+    }
+    window.addEventListener('message', window.onMessage);
+  </script>
+</body>
+</html>
\ No newline at end of file