From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../extensions/test/browser/head_devtools.js | 162 +++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 browser/components/extensions/test/browser/head_devtools.js (limited to 'browser/components/extensions/test/browser/head_devtools.js') diff --git a/browser/components/extensions/test/browser/head_devtools.js b/browser/components/extensions/test/browser/head_devtools.js new file mode 100644 index 0000000000..f46254d435 --- /dev/null +++ b/browser/components/extensions/test/browser/head_devtools.js @@ -0,0 +1,162 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +/* exported + assertDevToolsExtensionEnabled, + closeToolboxForTab, + navigateToWithDevToolsOpen + openToolboxForTab, + registerBlankToolboxPanel, + TOOLBOX_BLANK_PANEL_ID, +*/ + +ChromeUtils.defineESModuleGetters(this, { + loader: "resource://devtools/shared/loader/Loader.sys.mjs", + DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.sys.mjs", +}); +XPCOMUtils.defineLazyGetter(this, "gDevTools", () => { + const { gDevTools } = loader.require("devtools/client/framework/devtools"); + return gDevTools; +}); + +const TOOLBOX_BLANK_PANEL_ID = "testBlankPanel"; + +// Register a blank custom tool so that we don't need to wait the webconsole +// to be fully loaded/unloaded to prevent intermittent failures (related +// to a webconsole that is still loading when the test has been completed). +async function registerBlankToolboxPanel() { + const testBlankPanel = { + id: TOOLBOX_BLANK_PANEL_ID, + url: "about:blank", + label: "Blank Tool", + isToolSupported() { + return true; + }, + build(iframeWindow, toolbox) { + return Promise.resolve({ + target: toolbox.target, + toolbox: toolbox, + isReady: true, + panelDoc: iframeWindow.document, + destroy() {}, + }); + }, + }; + + registerCleanupFunction(() => { + gDevTools.unregisterTool(testBlankPanel.id); + }); + + gDevTools.registerTool(testBlankPanel); +} + +async function openToolboxForTab(tab, panelId = TOOLBOX_BLANK_PANEL_ID) { + if ( + panelId == TOOLBOX_BLANK_PANEL_ID && + !gDevTools.getToolDefinition(panelId) + ) { + info(`Registering ${TOOLBOX_BLANK_PANEL_ID} tool to the developer tools`); + registerBlankToolboxPanel(); + } + + const toolbox = await gDevTools.showToolboxForTab(tab, { toolId: panelId }); + const { url, outerWindowID } = toolbox.target.form; + info( + `Developer toolbox opened on panel "${panelId}" for target ${JSON.stringify( + { url, outerWindowID } + )}` + ); + return toolbox; +} + +async function closeToolboxForTab(tab) { + await gDevTools.closeToolboxForTab(tab); + const tabUrl = tab.linkedBrowser.currentURI.spec; + info(`Developer toolbox closed for tab "${tabUrl}"`); +} + +function assertDevToolsExtensionEnabled(uuid, enabled) { + for (let toolbox of DevToolsShim.getToolboxes()) { + is( + enabled, + !!toolbox.isWebExtensionEnabled(uuid), + `extension is ${enabled ? "enabled" : "disabled"} on toolbox` + ); + } +} + +/** + * Navigate the currently selected tab to a new URL and wait for it to load. + * Also wait for the toolbox to attach to the new target, if we navigated + * to a new process. + * + * @param {object} tab The tab to redirect. + * @param {string} uri The url to be loaded in the current tab. + * @param {boolean} isErrorPage You may pass `true` is the URL is an error + * page. Otherwise BrowserTestUtils.browserLoaded will wait + * for 'load' event, which never fires for error pages. + * + * @returns {Promise} A promise that resolves when the page has fully loaded. + */ +async function navigateToWithDevToolsOpen(tab, uri, isErrorPage = false) { + const toolbox = await gDevTools.getToolboxForTab(tab); + const target = toolbox.target; + + // If we're switching origins, we need to wait for the 'switched-target' + // event to make sure everything is ready. + // Navigating from/to pages loaded in the parent process, like about:robots, + // also spawn new targets. + // (If target switching is disabled, the toolbox will reboot) + const onTargetSwitched = + toolbox.commands.targetCommand.once("switched-target"); + // Otherwise, if we don't switch target, it is safe to wait for navigate event. + const onNavigate = target.once("navigate"); + + // If the current top-level target follows the window global lifecycle, a + // target switch will occur regardless of process changes. + const targetFollowsWindowLifecycle = + target.targetForm.followWindowGlobalLifeCycle; + + info(`Load document "${uri}"`); + const browser = gBrowser.selectedBrowser; + const currentPID = browser.browsingContext.currentWindowGlobal.osPid; + const currentBrowsingContextID = browser.browsingContext.id; + const onBrowserLoaded = BrowserTestUtils.browserLoaded( + browser, + false, + null, + isErrorPage + ); + BrowserTestUtils.loadURIString(browser, uri); + + info(`Waiting for page to be loaded…`); + await onBrowserLoaded; + info(`→ page loaded`); + + // Compare the PIDs (and not the toolbox's targets) as PIDs are updated also immediately, + // while target may be updated slightly later. + const switchedToAnotherProcess = + currentPID !== browser.browsingContext.currentWindowGlobal.osPid; + const switchedToAnotherBrowsingContext = + currentBrowsingContextID !== browser.browsingContext.id; + + // If: + // - the tab navigated to another process, or, + // - the tab navigated to another browsing context, or, + // - if the old target follows the window lifecycle + // then, expect a target switching. + if ( + switchedToAnotherProcess || + targetFollowsWindowLifecycle || + switchedToAnotherBrowsingContext + ) { + info(`Waiting for target switch…`); + await onTargetSwitched; + info(`→ switched-target emitted`); + } else { + info(`Waiting for target 'navigate' event…`); + await onNavigate; + info(`→ 'navigate' emitted`); + } +} -- cgit v1.2.3