commit 33ffbbf1b530d1d0a1e037687166a08e5da2036b
parent 2cb2c86b05424198a6eb62b5c7f782d1bdfdf313
Author: Alexandre Poirot <poirot.alex@gmail.com>
Date: Mon, 6 Oct 2025 10:19:18 +0000
Bug 1991420 - [devtools] Prevent any further execution once actions are cancelled. r=devtools-reviewers,nchevobbe
This uses a pattern similar to DebuggerContextError exception.
Once the panel closes, we start throwing exception to prevent any further code from running.
As for DebuggerContextError, we need to ignore these exceptions while running tests.
Differential Revision: https://phabricator.services.mozilla.com/D267184
Diffstat:
3 files changed, 34 insertions(+), 35 deletions(-)
diff --git a/devtools/client/shared/redux/middleware/ignore.js b/devtools/client/shared/redux/middleware/ignore.js
@@ -21,11 +21,11 @@ function ignore({ getState }) {
}
if (getState()[IGNORING]) {
- // We only print the action type, and not the whole action object, as it can holds
- // very complex data that would clutter stdout logs and make them impossible
- // to parse for treeherder.
- console.warn("IGNORED REDUX ACTION:", action.type);
- return null;
+ // Throw to stop execution from the callsite and prevent any further code from running
+ throw new Error(
+ "[REDUX_MIDDLEWARE_IGNORED_REDUX_ACTION] Dispatching '" + action.type ||
+ action + "' action after panel's closing"
+ );
}
return next(action);
diff --git a/devtools/client/shared/test/shared-head.js b/devtools/client/shared/test/shared-head.js
@@ -19,6 +19,15 @@ for (const pref of devtoolsPreferences.getChildList("")) {
}
}
+{
+ const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+ );
+ PromiseTestUtils.allowMatchingRejectionsGlobally(
+ /REDUX_MIDDLEWARE_IGNORED_REDUX_ACTION/
+ );
+}
+
async function resetPreferencesModifiedDuringTest() {
if (!isXpcshell) {
await SpecialPowers.flushPrefEnv();
diff --git a/devtools/startup/tests/browser/browser_command_line_urls.js b/devtools/startup/tests/browser/browser_command_line_urls.js
@@ -7,16 +7,18 @@
* Test command line processing of URLs meant to be intepreted by DevTools.
*/
-const { DevToolsStartup } = ChromeUtils.importESModule(
- "resource:///modules/DevToolsStartup.sys.mjs"
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
+ this
);
-
-const { require } = ChromeUtils.importESModule(
- "resource://devtools/shared/loader/Loader.sys.mjs"
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/debugger/test/mochitest/shared-head.js",
+ this
);
-const { gDevTools } = require("devtools/client/framework/devtools");
-const URL_ROOT = "https://example.org/browser/devtools/startup/tests/browser/";
+const { DevToolsStartup } = ChromeUtils.importESModule(
+ "resource:///modules/DevToolsStartup.sys.mjs"
+);
const startup = new DevToolsStartup();
// The feature covered here only work when calling firefox from command line
@@ -56,7 +58,7 @@ add_task(async function ignoredUrls() {
* the url will be ignored
*/
add_task(async function openingWithDevToolsClosed() {
- const url = URL_ROOT + "command-line.html:5:2";
+ const url = URL_ROOT_SSL + "command-line.html:5:2";
const tabCount = gBrowser.tabs.length;
const ignoredUrl = sendUrlViaCommandLine(url);
@@ -73,7 +75,7 @@ add_task(async function openingWithDevToolsClosed() {
* the url will also be opened via view-source
*/
add_task(async function openingWithDevToolsButUnknownSource() {
- const url = URL_ROOT + "command-line.html:5:2";
+ const url = URL_ROOT_SSL + "command-line.html:5:2";
const tab = BrowserTestUtils.addTab(
gBrowser,
@@ -90,7 +92,7 @@ add_task(async function openingWithDevToolsButUnknownSource() {
const newTab = await newTabOpened;
is(
newTab.linkedBrowser.documentURI.spec,
- "view-source:" + URL_ROOT + "command-line.html"
+ "view-source:" + URL_ROOT_SSL + "command-line.html"
);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
@@ -117,11 +119,11 @@ add_task(async function openingWithDevToolsButUnknownSource() {
add_task(async function openingWithDevToolsAndKnownSource() {
const line = 5;
const column = 2;
- const url = URL_ROOT + `command-line.js:${line}:${column}`;
+ const url = URL_ROOT_SSL + `command-line.js:${line}:${column}`;
const tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
- URL_ROOT + "command-line.html"
+ URL_ROOT_SSL + "command-line.html"
);
const toolbox = await gDevTools.showToolboxForTab(tab, {
toolId: "jsdebugger",
@@ -130,28 +132,16 @@ add_task(async function openingWithDevToolsAndKnownSource() {
info("Open a first URL with line and column");
sendUrlViaCommandLine(url);
- const dbg = toolbox.getPanel("jsdebugger");
- // Wait for the expected location to be selected and ignore any other default ones.
- const selectedLocation = await BrowserTestUtils.waitForCondition(() => {
- const location = dbg._selectors.getSelectedLocation(dbg._getState());
- return location?.line == line ? location : false;
- });
-
- is(selectedLocation.source.url, URL_ROOT + "command-line.js");
- is(selectedLocation.line, line);
- is(selectedLocation.column, column - 1);
+ const dbg = createDebuggerContext(toolbox);
+ await waitForSelectedSource(dbg, "command-line.js");
+ await waitForSelectedLocation(dbg, line, column);
info("Open another URL with only a line");
const secondLine = 6;
- const url2 = URL_ROOT + `command-line.js:${secondLine}`;
+ const url2 = URL_ROOT_SSL + `command-line.js:${secondLine}`;
sendUrlViaCommandLine(url2);
- const selectedLocation2 = await BrowserTestUtils.waitForCondition(() => {
- const location = dbg._selectors.getSelectedLocation(dbg._getState());
- return location.line == secondLine ? location : false;
- });
- is(selectedLocation2.source.url, URL_ROOT + "command-line.js");
- is(selectedLocation2.line, secondLine);
- is(selectedLocation2.column, 0);
+ await waitForSelectedSource(dbg, "command-line.js");
+ await waitForSelectedLocation(dbg, secondLine, 1);
await toolbox.destroy();
await gBrowser.removeTab(tab);