summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_incognito_views.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/browser/browser_ext_incognito_views.js')
-rw-r--r--browser/components/extensions/test/browser/browser_ext_incognito_views.js269
1 files changed, 269 insertions, 0 deletions
diff --git a/browser/components/extensions/test/browser/browser_ext_incognito_views.js b/browser/components/extensions/test/browser/browser_ext_incognito_views.js
new file mode 100644
index 0000000000..8a7c3219b3
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_incognito_views.js
@@ -0,0 +1,269 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_setup(async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.openPopupWithoutUserGesture.enabled", true]],
+ });
+});
+
+add_task(async function testIncognitoViews() {
+ // Make sure the mouse isn't hovering over the browserAction widget.
+ EventUtils.synthesizeMouseAtCenter(
+ gURLBar.textbox,
+ { type: "mouseover" },
+ window
+ );
+
+ let extension = ExtensionTestUtils.loadExtension({
+ incognitoOverride: "spanning",
+ manifest: {
+ permissions: ["tabs"],
+ description: JSON.stringify({
+ headless: Services.env.get("MOZ_HEADLESS"),
+ debug: AppConstants.DEBUG,
+ }),
+ browser_action: {
+ default_popup: "popup.html",
+ default_area: "navbar",
+ },
+ },
+
+ background: async function () {
+ window.isBackgroundPage = true;
+ const { headless, debug } = JSON.parse(
+ browser.runtime.getManifest().description
+ );
+
+ class ConnectedPopup {
+ #msgPromise;
+ #disconnectPromise;
+
+ static promiseNewPopup() {
+ return new Promise(resolvePort => {
+ browser.runtime.onConnect.addListener(function onConnect(port) {
+ browser.runtime.onConnect.removeListener(onConnect);
+ browser.test.assertEq("from-popup", port.name, "Port from popup");
+ resolvePort(new ConnectedPopup(port));
+ });
+ });
+ }
+
+ constructor(port) {
+ this.port = port;
+ this.#msgPromise = new Promise(resolveMessage => {
+ // popup.js sends one message with the popup's metadata.
+ port.onMessage.addListener(resolveMessage);
+ });
+ this.#disconnectPromise = new Promise(resolveDisconnect => {
+ port.onDisconnect.addListener(resolveDisconnect);
+ });
+ }
+
+ async getPromisedMessage() {
+ browser.test.log("Waiting for popup to send information");
+ let msg = await this.#msgPromise;
+ browser.test.assertEq("popup-details", msg.message, "Got port msg");
+ return msg;
+ }
+
+ async promisePopupClosed(desc) {
+ browser.test.log(`Waiting for popup to be closed (${desc})`);
+ // There is currently no great way for extension to detect a closed
+ // popup. Extensions can observe the port.onDisconnect event for now.
+ await this.#disconnectPromise;
+ browser.test.log(`Popup was closed (${desc})`);
+ }
+
+ async closePopup(desc) {
+ browser.test.log(`Closing popup (${desc})`);
+ this.port.postMessage("close_popup");
+ return this.promisePopupClosed(desc);
+ }
+ }
+
+ let testPopupForWindow = async window => {
+ let popupConnectionPromise = ConnectedPopup.promiseNewPopup();
+
+ await browser.browserAction.openPopup({
+ windowId: window.id,
+ });
+
+ let connectedPopup = await popupConnectionPromise;
+ let msg = await connectedPopup.getPromisedMessage();
+ browser.test.assertEq(
+ window.id,
+ msg.windowId,
+ "Got popup message from correct window"
+ );
+ browser.test.assertEq(
+ window.incognito,
+ msg.incognito,
+ "Correct incognito status in browserAction popup"
+ );
+
+ return connectedPopup;
+ };
+
+ async function createPrivateWindow() {
+ const URL = "https://example.com/?dummy-incognito-window";
+ let windowReady = new Promise(resolve => {
+ browser.tabs.onUpdated.addListener(function l(tabId, changed, tab) {
+ if (changed.status == "complete" && tab.url == URL) {
+ browser.tabs.onUpdated.removeListener(l);
+ resolve();
+ }
+ });
+ });
+ let window = await browser.windows.create({
+ incognito: true,
+ url: URL,
+ });
+ await windowReady;
+ return window;
+ }
+
+ function getNonPrivateViewCount() {
+ // The background context is in non-private browsing mode, so getViews()
+ // only returns the views that are not in private browsing mode.
+ return browser.extension.getViews({ type: "popup" }).length;
+ }
+
+ try {
+ let nonPrivatePopup;
+ {
+ let window = await browser.windows.getCurrent();
+
+ nonPrivatePopup = await testPopupForWindow(window);
+
+ browser.test.assertEq(1, getNonPrivateViewCount(), "popup is open");
+ // ^ The popup will close when a new window is opened below.
+ if (headless) {
+ // ... except when --headless is used. For some reason, the popup
+ // does not close when another window is opened. Close manually.
+ await nonPrivatePopup.closePopup("Work-around for --headless bug");
+ }
+ }
+
+ {
+ let window = await createPrivateWindow();
+
+ let privatePopup = await testPopupForWindow(window);
+
+ await nonPrivatePopup.promisePopupClosed("First popup closed by now");
+
+ browser.test.assertEq(
+ 0,
+ getNonPrivateViewCount(),
+ "First popup should have been closed when a new window was opened"
+ );
+
+ // TODO bug 1809000: On debug builds, a memory leak is reported when
+ // the popup is closed as part of closing a window. As a work-around,
+ // we explicitly close the popup here.
+ // TODO: Remove when bug 1809000 is fixed.
+ if (debug) {
+ await privatePopup.closePopup("Work-around for bug 1809000");
+ }
+
+ await browser.windows.remove(window.id);
+ // ^ This also closes the popup panel associated with the window. If
+ // it somehow does not close properly, errors may be reported, e.g.
+ // leakcheck failures in debug mode (like bug 1800100).
+
+ // This check is not strictly necessary, but we're doing this to
+ // confirm that the private popup has indeed been closed.
+ await privatePopup.promisePopupClosed("Window closed = popup gone");
+ }
+
+ browser.test.notifyPass("incognito-views");
+ } catch (error) {
+ browser.test.fail(`Error: ${error} :: ${error.stack}`);
+ browser.test.notifyFail("incognito-views");
+ }
+ },
+
+ files: {
+ "popup.html":
+ '<html><head><meta charset="utf-8"><script src="popup.js"></script></head></html>',
+
+ "popup.js": async function () {
+ let views = browser.extension.getViews();
+
+ if (browser.extension.inIncognitoContext) {
+ let bgPage = browser.extension.getBackgroundPage();
+ browser.test.assertEq(
+ null,
+ bgPage,
+ "Should not be able to access background page in incognito context"
+ );
+
+ bgPage = await browser.runtime.getBackgroundPage();
+ browser.test.assertEq(
+ null,
+ bgPage,
+ "Should not be able to access background page in incognito context"
+ );
+
+ browser.test.assertEq(
+ 1,
+ views.length,
+ "Should only see one view in incognito popup"
+ );
+ browser.test.assertEq(
+ window,
+ views[0],
+ "This window should be the only view"
+ );
+ } else {
+ let bgPage = browser.extension.getBackgroundPage();
+ browser.test.assertEq(
+ true,
+ bgPage.isBackgroundPage,
+ "Should be able to access background page in non-incognito context"
+ );
+
+ bgPage = await browser.runtime.getBackgroundPage();
+ browser.test.assertEq(
+ true,
+ bgPage.isBackgroundPage,
+ "Should be able to access background page in non-incognito context"
+ );
+
+ browser.test.assertEq(
+ 2,
+ views.length,
+ "Should only two views in non-incognito popup"
+ );
+ browser.test.assertEq(
+ bgPage,
+ views[0],
+ "The background page should be the first view"
+ );
+ browser.test.assertEq(
+ window,
+ views[1],
+ "This window should be the second view"
+ );
+ }
+
+ let win = await browser.windows.getCurrent();
+ let port = browser.runtime.connect({ name: "from-popup" });
+ port.onMessage.addListener(msg => {
+ browser.test.assertEq("close_popup", msg, "Close popup msg");
+ window.close();
+ });
+ port.postMessage({
+ message: "popup-details",
+ windowId: win.id,
+ incognito: browser.extension.inIncognitoContext,
+ });
+ },
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("incognito-views");
+ await extension.unload();
+});