mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1774937 - [devtools] Allow to debug slow script without having devtools opened beforehand. r=jdescottes
The test doesn't really cover this fix as mochitest head files will force loading gDevTools... To properly cover that we would have to have this test in another file and folder without any head. This will make it hard to reuse Debugger test helpers. Let's assume we cover the modified feature while not covering the very precise regression I fix here. Differential Revision: https://phabricator.services.mozilla.com/D150155
This commit is contained in:
parent
d3f1f1cf11
commit
1ae58de96b
@ -39,3 +39,53 @@ add_task(async function openDebuggerFirst() {
|
||||
await dbg.toolbox.closeToolbox();
|
||||
await removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(async function openDebuggerFromDialog() {
|
||||
const tab = await addTab(EXAMPLE_URL + "doc-slow-script.html");
|
||||
|
||||
const alert = BrowserTestUtils.waitForGlobalNotificationBar(
|
||||
window,
|
||||
"process-hang"
|
||||
);
|
||||
|
||||
// /!\ Hack this attribute in order to force showing the "debug script" button
|
||||
// on all channels. Otherwise it is only displayed in dev edition.
|
||||
tab.linkedBrowser.browsingContext.watchedByDevTools = true;
|
||||
|
||||
info("Execute an infinite loop");
|
||||
// Note that spawn will return a promise that may be rejected because of the infinite loop
|
||||
// And mochitest may consider this as an error. So ignore any rejection.
|
||||
SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
|
||||
content.wrappedJSObject.infiniteLoop();
|
||||
}).catch(e => {});
|
||||
|
||||
info("Wait for the slow script warning");
|
||||
const notification = await alert;
|
||||
|
||||
info("Click on the debug script button");
|
||||
const buttons = notification.buttonContainer.getElementsByTagName("button");
|
||||
// The first button is "stop", the second is "debug script"
|
||||
buttons[1].click();
|
||||
|
||||
info("Wait for the toolbox to appear and have the debugger initialized");
|
||||
await waitFor(async () => {
|
||||
const tb = await gDevTools.getToolboxForTab(gBrowser.selectedTab);
|
||||
if (tb) {
|
||||
await tb.getPanelWhenReady("jsdebugger");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const toolbox = await gDevTools.getToolboxForTab(gBrowser.selectedTab);
|
||||
ok(toolbox, "Got a toolbox");
|
||||
const dbg = createDebuggerContext(toolbox);
|
||||
|
||||
info("Waiting for the debugger to be paused");
|
||||
await waitForPaused(dbg);
|
||||
const source = findSource(dbg, "doc-slow-script.html");
|
||||
assertPausedAtSourceAndLine(dbg, source.id, 14);
|
||||
|
||||
info("Close toolbox and tab");
|
||||
await dbg.toolbox.closeToolbox();
|
||||
await removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
@ -12,7 +12,6 @@
|
||||
* browser window is ready (i.e. fired browser-delayed-startup-finished event)
|
||||
**/
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const {
|
||||
@ -465,83 +464,6 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hook the JS debugger tool to the "Debug Script" button of the slow script
|
||||
* dialog.
|
||||
*/
|
||||
setSlowScriptDebugHandler() {
|
||||
const debugService = Cc["@mozilla.org/dom/slow-script-debug;1"].getService(
|
||||
Ci.nsISlowScriptDebug
|
||||
);
|
||||
|
||||
async function slowScriptDebugHandler(tab, callback) {
|
||||
const toolbox = await gDevTools.showToolboxForTab(tab, {
|
||||
toolId: "jsdebugger",
|
||||
});
|
||||
const threadFront = toolbox.threadFront;
|
||||
|
||||
// Break in place, which means resuming the debuggee thread and pausing
|
||||
// right before the next step happens.
|
||||
switch (threadFront.state) {
|
||||
case "paused":
|
||||
// When the debugger is already paused.
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
case "attached":
|
||||
// When the debugger is already open.
|
||||
const onPaused = threadFront.once("paused");
|
||||
threadFront.interrupt();
|
||||
await onPaused;
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
case "resuming":
|
||||
// The debugger is newly opened.
|
||||
const onResumed = threadFront.once("resumed");
|
||||
await threadFront.interrupt();
|
||||
await onResumed;
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
default:
|
||||
throw Error(
|
||||
"invalid thread front state in slow script debug handler: " +
|
||||
threadFront.state
|
||||
);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
debugService.activationHandler = function(window) {
|
||||
const chromeWindow = window.browsingContext.topChromeWindow;
|
||||
|
||||
let setupFinished = false;
|
||||
slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab, () => {
|
||||
setupFinished = true;
|
||||
});
|
||||
|
||||
// Don't return from the interrupt handler until the debugger is brought
|
||||
// up; no reason to continue executing the slow script.
|
||||
const utils = window.windowUtils;
|
||||
utils.enterModalState();
|
||||
Services.tm.spinEventLoopUntil(
|
||||
"devtools-browser.js:debugService.activationHandler",
|
||||
() => {
|
||||
return setupFinished;
|
||||
}
|
||||
);
|
||||
utils.leaveModalState();
|
||||
};
|
||||
|
||||
debugService.remoteActivationHandler = function(browser, callback) {
|
||||
const chromeWindow = browser.ownerDocument.defaultView;
|
||||
const tab = chromeWindow.gBrowser.getTabForBrowser(browser);
|
||||
chromeWindow.gBrowser.selected = tab;
|
||||
|
||||
slowScriptDebugHandler(tab, function() {
|
||||
callback.finishDebuggerStartup();
|
||||
}).catch(console.error);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the menuitem for a tool to all open browser windows.
|
||||
*
|
||||
@ -771,8 +693,6 @@ gDevTools.on("tool-registered", function(toolId) {
|
||||
}
|
||||
});
|
||||
|
||||
gDevToolsBrowser.setSlowScriptDebugHandler();
|
||||
|
||||
gDevTools.on("tool-unregistered", function(toolId) {
|
||||
gDevToolsBrowser._removeToolFromWindows(toolId);
|
||||
});
|
||||
|
@ -479,6 +479,7 @@ DevToolsStartup.prototype = {
|
||||
this.sendEntryPointTelemetry("CommandLine");
|
||||
}
|
||||
}
|
||||
this.setSlowScriptDebugHandler();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1094,6 +1095,92 @@ DevToolsStartup.prototype = {
|
||||
this.recorded = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hook the debugger tool to the "Debug Script" button of the slow script dialog.
|
||||
*/
|
||||
setSlowScriptDebugHandler() {
|
||||
const debugService = Cc["@mozilla.org/dom/slow-script-debug;1"].getService(
|
||||
Ci.nsISlowScriptDebug
|
||||
);
|
||||
|
||||
debugService.activationHandler = window => {
|
||||
const chromeWindow = window.browsingContext.topChromeWindow;
|
||||
|
||||
let setupFinished = false;
|
||||
this.slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab).then(
|
||||
() => {
|
||||
setupFinished = true;
|
||||
}
|
||||
);
|
||||
|
||||
// Don't return from the interrupt handler until the debugger is brought
|
||||
// up; no reason to continue executing the slow script.
|
||||
const utils = window.windowUtils;
|
||||
utils.enterModalState();
|
||||
Services.tm.spinEventLoopUntil(
|
||||
"devtools-browser.js:debugService.activationHandler",
|
||||
() => {
|
||||
return setupFinished;
|
||||
}
|
||||
);
|
||||
utils.leaveModalState();
|
||||
};
|
||||
|
||||
debugService.remoteActivationHandler = async (browser, callback) => {
|
||||
try {
|
||||
// Force selecting the freezing tab
|
||||
const chromeWindow = browser.ownerGlobal;
|
||||
const tab = chromeWindow.gBrowser.getTabForBrowser(browser);
|
||||
chromeWindow.gBrowser.selectedTab = tab;
|
||||
|
||||
await this.slowScriptDebugHandler(tab);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
callback.finishDebuggerStartup();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by setSlowScriptDebugHandler, when a tab freeze because of a slow running script
|
||||
*/
|
||||
async slowScriptDebugHandler(tab) {
|
||||
const require = this.initDevTools("SlowScript");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const toolbox = await gDevTools.showToolboxForTab(tab, {
|
||||
toolId: "jsdebugger",
|
||||
});
|
||||
const threadFront = toolbox.threadFront;
|
||||
|
||||
// Break in place, which means resuming the debuggee thread and pausing
|
||||
// right before the next step happens.
|
||||
switch (threadFront.state) {
|
||||
case "paused":
|
||||
// When the debugger is already paused.
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
case "attached":
|
||||
// When the debugger is already open.
|
||||
const onPaused = threadFront.once("paused");
|
||||
threadFront.interrupt();
|
||||
await onPaused;
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
case "resuming":
|
||||
// The debugger is newly opened.
|
||||
const onResumed = threadFront.once("resumed");
|
||||
await threadFront.interrupt();
|
||||
await onResumed;
|
||||
threadFront.resumeThenPause();
|
||||
break;
|
||||
default:
|
||||
throw Error(
|
||||
"invalid thread front state in slow script debug handler: " +
|
||||
threadFront.state
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Used by tests and the toolbox to register the same key shortcuts in toolboxes loaded
|
||||
// in a window window.
|
||||
get KeyShortcuts() {
|
||||
|
@ -1780,7 +1780,7 @@ devtools.main:
|
||||
release_channel_collection: opt-out
|
||||
expiry_version: never
|
||||
extra_keys:
|
||||
entrypoint: How was the toolbox opened? CommandLine, ContextMenu, HamburgerMenu, KeyShortcut, SessionRestore or SystemMenu
|
||||
entrypoint: How was the toolbox opened? CommandLine, ContextMenu, HamburgerMenu, KeyShortcut, SessionRestore, SystemMenu or SlowScript
|
||||
first_panel: The name of the first panel opened.
|
||||
host: "Toolbox host (positioning): bottom, side, window or other."
|
||||
splitconsole: Indicates whether the split console was open.
|
||||
|
@ -11385,7 +11385,7 @@
|
||||
"alert_emails": ["dev-developer-tools@lists.mozilla.org", "apoirot@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "categorical",
|
||||
"labels": ["KeyShortcut", "SystemMenu", "HamburgerMenu", "ContextMenu", "CommandLine", "SessionRestore"],
|
||||
"labels": ["KeyShortcut", "SystemMenu", "HamburgerMenu", "ContextMenu", "CommandLine", "SessionRestore", "SlowScript"],
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"description": "Records how the user is triggering Developer Tools startup."
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user