Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

/* -*- 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() {
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();
});