/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; var { ContextDescriptorType } = ChromeUtils.importESModule( "chrome://remote/content/shared/messagehandler/MessageHandler.sys.mjs" ); var { WindowGlobalMessageHandler } = ChromeUtils.importESModule( "chrome://remote/content/shared/messagehandler/WindowGlobalMessageHandler.sys.mjs" ); var contextDescriptorAll = { type: ContextDescriptorType.All, }; function createRootMessageHandler(sessionId) { const { RootMessageHandlerRegistry } = ChromeUtils.importESModule( "chrome://remote/content/shared/messagehandler/RootMessageHandlerRegistry.sys.mjs" ); return RootMessageHandlerRegistry.getOrCreateMessageHandler(sessionId); } /** * Load the provided url in an existing browser. * Returns a promise which will resolve when the page is loaded. * * @param {Browser} browser * The browser element where the URL should be loaded. * @param {string} url * The URL to load in the new tab */ async function loadURL(browser, url) { const loaded = BrowserTestUtils.browserLoaded(browser); BrowserTestUtils.startLoadingURIString(browser, url); return loaded; } /** * Create a new foreground tab loading the provided url. * Returns a promise which will resolve when the page is loaded. * * @param {string} url * The URL to load in the new tab */ async function addTab(url) { const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); registerCleanupFunction(() => { gBrowser.removeTab(tab); }); return tab; } /** * Create inline markup for a simple iframe that can be used with * document-builder.sjs. The iframe will be served under the provided domain. * * @param {string} domain * A domain (eg "example.com"), compatible with build/pgo/server-locations.txt */ function createFrame(domain) { return createFrameForUri( `https://${domain}/document-builder.sjs?html=frame-${domain}` ); } function createFrameForUri(uri) { return ``; } /** * Create a XUL browser element in the provided XUL tab, with the provided type. * * @param {XULTab} tab * The XUL tab in which the browser element should be inserted. * @param {string} type * The type attribute of the browser element, "chrome" or "content". * @returns {XULBrowser} * The created browser element. */ function createParentBrowserElement(tab, type) { const parentBrowser = gBrowser.ownerDocument.createXULElement("browser"); parentBrowser.setAttribute("type", type); const container = gBrowser.getBrowserContainer(tab.linkedBrowser); container.appendChild(parentBrowser); return parentBrowser; } // Create a test page with 2 iframes: // - one with a different eTLD+1 (example.com) // - one with a nested iframe on a different eTLD+1 (example.net) // // Overall the document structure should look like: // // html (example.org) // iframe (example.org) // iframe (example.net) // iframe(example.com) // // Which means we should have 4 browsing contexts in total. function createTestMarkupWithFrames() { // Create the markup for an example.net frame nested in an example.com frame. const NESTED_FRAME_MARKUP = createFrameForUri( `https://example.org/document-builder.sjs?html=${createFrame( "example.net" )}` ); // Combine the nested frame markup created above with an example.com frame. const TEST_URI_MARKUP = `${NESTED_FRAME_MARKUP}${createFrame("example.com")}`; // Create the test page URI on example.org. return `https://example.org/document-builder.sjs?html=${encodeURI( TEST_URI_MARKUP )}`; } const hasPromiseResolved = async function (promise) { let resolved = false; promise.finally(() => (resolved = true)); // Make sure microtasks have time to run. await new Promise(resolve => Services.tm.dispatchToMainThread(resolve)); return resolved; }; /** * Install a sidebar extension. * * @returns {object} * Return value with two properties: * - extension: test wrapper as returned by SpecialPowers.loadExtension. * Make sure to explicitly call extension.unload() before the end of the test. * - sidebarBrowser: the browser element containing the extension sidebar. */ async function installSidebarExtension() { info("Load the test extension"); let extension = ExtensionTestUtils.loadExtension({ manifest: { sidebar_action: { default_panel: "sidebar.html", }, }, useAddonManager: "temporary", files: { "sidebar.html": ` Test extension `, "sidebar.js": function () { const { browser } = this; browser.test.sendMessage("sidebar-loaded", { bcId: SpecialPowers.wrap(window).browsingContext.id, }); }, "tab.html": ` Test extension (tab) `, "tab.js": function () { const { browser } = this; browser.test.sendMessage("tab-loaded", { bcId: SpecialPowers.wrap(window).browsingContext.id, }); }, }, }); info("Wait for the extension to start"); await extension.startup(); info("Wait for the extension browsing context"); const { bcId } = await extension.awaitMessage("sidebar-loaded"); const sidebarBrowser = BrowsingContext.get(bcId).top.embedderElement; ok(sidebarBrowser, "Got a browser element for the extension sidebar"); return { extension, sidebarBrowser, }; } const SessionDataUpdateHelpers = { getUpdates(rootMessageHandler, browsingContext) { return rootMessageHandler.handleCommand({ moduleName: "sessiondataupdate", commandName: "getSessionDataUpdates", destination: { id: browsingContext.id, type: WindowGlobalMessageHandler.type, }, }); }, createSessionDataUpdate( values, method, category, descriptor = { type: ContextDescriptorType.All } ) { return { method, values, moduleName: "sessiondataupdate", category, contextDescriptor: descriptor, }; }, assertUpdate(update, expectedValues, expectedCategory) { is( update.length, expectedValues.length, "Update has the expected number of values" ); for (const item of update) { info(`Check session data update item '${item.value}'`); is(item.category, expectedCategory, "Item has the expected category"); is( expectedValues[update.indexOf(item)], item.value, "Item has the expected value" ); } }, };