/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/devtools/client/debugger/test/mochitest/shared-head.js", this ); /* import-globals-from helper-addons.js */ Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-addons.js", this); const L10N = new LocalizationHelper( "devtools/client/locales/toolbox.properties" ); const EXTENSION_NAME = "temporary-web-extension"; const EXTENSION_ID = "test-devtools@mozilla.org"; add_task(async function testOpenDebuggerReload() { await enableExtensionDebugging(); info( "The debugger should show the source codes of extension even if " + "devtools.chrome.enabled and devtools.debugger.remote-enabled are off" ); await pushPref("devtools.chrome.enabled", false); await pushPref("devtools.debugger.remote-enabled", false); const { document, tab, window } = await openAboutDebugging(); await selectThisFirefoxPage(document, window.AboutDebugging.store); await installTemporaryExtensionFromXPI( { background() { window.someRandomMethodName = () => { // This will not be referred from anywhere. // However this is necessary to show as the source code in the debugger. }; }, id: EXTENSION_ID, name: EXTENSION_NAME, }, document ); // Select the debugger right away to avoid any noise coming from the inspector. await pushPref("devtools.toolbox.selectedTool", "jsdebugger"); const { devtoolsWindow } = await openAboutDevtoolsToolbox( document, tab, window, EXTENSION_NAME ); const toolbox = getToolbox(devtoolsWindow); const { panelWin } = toolbox.getCurrentPanel(); info("Check the state of redux"); ok( panelWin.dbg.store.getState().sourcesTree.isWebExtension, "isWebExtension flag in sourcesTree is true" ); const descriptorTitle = devtoolsWindow.document.querySelector( ".qa-descriptor-title" ); is( descriptorTitle.textContent, EXTENSION_NAME, "The add-on name is displayed in the toolbox header" ); info("Check whether the element displays correctly"); let sourceList = panelWin.document.querySelector(".sources-list"); ok(sourceList, "Source list element displays correctly"); ok( sourceList.textContent.includes("temporary-web-extension"), "Extension name displays correctly" ); const { onResource: onDomCompleteResource } = await toolbox.commands.resourceCommand.waitForNextResource( toolbox.commands.resourceCommand.TYPES.DOCUMENT_EVENT, { ignoreExistingResources: true, predicate: resource => { return ( resource.name === "dom-complete" && resource.targetFront.url.endsWith("background_page.html") ); }, } ); info("Reload the addon using a toolbox reload shortcut"); toolbox.win.focus(); synthesizeKeyShortcut(L10N.getStr("toolbox.reload.key"), toolbox.win); await onDomCompleteResource; info("Wait until a new background log message is logged"); await waitFor(() => { // As React may re-create a new sources-list element, // fetch the latest instance sourceList = panelWin.document.querySelector(".sources-list"); return sourceList?.textContent.includes("temporary-web-extension"); }, "Wait for the source to re-appear"); await closeWebExtAboutDevtoolsToolbox(devtoolsWindow, window); await removeTemporaryExtension(EXTENSION_NAME, document); await removeTab(tab); }); add_task(async function testAddAndRemoveBreakpoint() { await enableExtensionDebugging(); const { document, tab, window } = await openAboutDebugging(); await selectThisFirefoxPage(document, window.AboutDebugging.store); await installTemporaryExtensionFromXPI( { background() { window.invokeLogFromWebextension = () => { console.log("From webextension"); }; }, id: EXTENSION_ID, name: EXTENSION_NAME, }, document ); // Select the debugger right away to avoid any noise coming from the inspector. await pushPref("devtools.toolbox.selectedTool", "jsdebugger"); const { devtoolsWindow } = await openAboutDevtoolsToolbox( document, tab, window, EXTENSION_NAME ); const toolbox = getToolbox(devtoolsWindow); const dbg = createDebuggerContext(toolbox); info("Assert the threads displayed in Source Tree as well as Threads pane"); const sourceTreeThreads = findAllElements(dbg, "sourceTreeThreads"); is( sourceTreeThreads.length, 1, "There is only one thread with source in the Source Tree" ); is( sourceTreeThreads[0].textContent, "/_generated_background_page.html", "That thread is the background page" ); const threadLabels = findAllElements(dbg, "threadsPaneItems"); is(threadLabels.length, 2, "But there are two threads in the thread panel"); is(threadLabels[0].textContent, "Web Extension Fallback Document"); is(threadLabels[1].textContent, "/_generated_background_page.html"); info("Select the source and add a breakpoint"); // Note: the background script filename is dynamically generated id, so we // simply get the first source from the list. const displayedSources = dbg.selectors.getDisplayedSourcesList(); const backgroundScript = displayedSources[0]; await selectSource(dbg, backgroundScript); await addBreakpoint(dbg, backgroundScript, 3); info("Trigger the breakpoint and wait for the debugger to pause"); const webconsole = await toolbox.selectTool("webconsole"); const { hud } = webconsole; hud.ui.wrapper.dispatchEvaluateExpression("invokeLogFromWebextension()"); await waitForPaused(dbg); info("Resume and remove the breakpoint"); await resume(dbg); await removeBreakpoint(dbg, backgroundScript.id, 3); info("Trigger the function again and check the debugger does not pause"); hud.ui.wrapper.dispatchEvaluateExpression("invokeLogFromWebextension()"); await wait(500); assertNotPaused(dbg); await closeWebExtAboutDevtoolsToolbox(devtoolsWindow, window); await removeTemporaryExtension(EXTENSION_NAME, document); await removeTab(tab); });