162 lines
5.3 KiB
JavaScript
162 lines
5.3 KiB
JavaScript
/* -*- 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",
|
|
});
|
|
ChromeUtils.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 = 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.startLoadingURIString(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`);
|
|
}
|
|
}
|