diff options
Diffstat (limited to 'devtools/shared/commands')
20 files changed, 178 insertions, 38 deletions
diff --git a/devtools/shared/commands/object/object-command.js b/devtools/shared/commands/object/object-command.js index 0396b6167a..5812f31148 100644 --- a/devtools/shared/commands/object/object-command.js +++ b/devtools/shared/commands/object/object-command.js @@ -21,10 +21,6 @@ class ObjectCommand { * List of fronts for the object to release. */ async releaseObjects(frontsToRelease) { - // @backward-compat { version 123 } A new Objects Manager front has a new "releaseActors" method. - // Only supportsReleaseActors=true codepath can be kept once 123 is the release channel. - const { supportsReleaseActors } = this.#commands.client.mainRoot.traits; - // First group all object fronts per target const actorsPerTarget = new Map(); const promises = []; @@ -40,20 +36,14 @@ class ObjectCommand { actorIDsToRemove = []; actorsPerTarget.set(targetFront, actorIDsToRemove); } - if (supportsReleaseActors) { - actorIDsToRemove.push(frontToRelease.actorID); - frontToRelease.destroy(); - } else { - promises.push(frontToRelease.release()); - } + actorIDsToRemove.push(frontToRelease.actorID); + frontToRelease.destroy(); } - if (supportsReleaseActors) { - // Then release all fronts by bulk per target - for (const [targetFront, actorIDs] of actorsPerTarget) { - const objectsManagerFront = await targetFront.getFront("objects-manager"); - promises.push(objectsManagerFront.releaseObjects(actorIDs)); - } + // Then release all fronts by bulk per target + for (const [targetFront, actorIDs] of actorsPerTarget) { + const objectsManagerFront = await targetFront.getFront("objects-manager"); + promises.push(objectsManagerFront.releaseObjects(actorIDs)); } await Promise.all(promises); diff --git a/devtools/shared/commands/resource/legacy-listeners/thread-states.js b/devtools/shared/commands/resource/legacy-listeners/thread-states.js index 42c922072a..b24bdfa8cc 100644 --- a/devtools/shared/commands/resource/legacy-listeners/thread-states.js +++ b/devtools/shared/commands/resource/legacy-listeners/thread-states.js @@ -56,7 +56,7 @@ module.exports = async function ({ targetCommand, targetFront, onAvailable }) { }; threadFront.on("paused", onPausedPacket); - threadFront.on("resumed", packet => { + threadFront.on("resumed", () => { // NOTE: the client suppresses resumed events while interrupted // to prevent unintentional behavior. // see [client docs](devtools/client/debugger/src/client/README.md#interrupted) for more information. diff --git a/devtools/shared/commands/resource/resource-command.js b/devtools/shared/commands/resource/resource-command.js index c45dc6a584..5b34bf4442 100644 --- a/devtools/shared/commands/resource/resource-command.js +++ b/devtools/shared/commands/resource/resource-command.js @@ -826,7 +826,7 @@ class ResourceCommand { * Called everytime a resource is destroyed in the remote target. * See _onResourceAvailable for the argument description. */ - async _onResourceDestroyed({ targetFront, watcherFront }, resources) { + async _onResourceDestroyed({ targetFront }, resources) { for (const resource of resources) { const { resourceType, resourceId } = resource; this._cache.delete(cacheKey(resourceType, resourceId)); @@ -923,7 +923,7 @@ class ResourceCommand { return null; } - _onWillNavigate(targetFront) { + _onWillNavigate() { // Special case for toolboxes debugging a document, // purge the cache entirely when we start navigating to a new document. // Other toolboxes and additional target for remote iframes or content process @@ -1243,11 +1243,7 @@ const WORKER_RESOURCE_TYPES = [ // Each section added here should eventually be removed once the equivalent server // code is implement in Firefox, in its release channel. const LegacyListeners = { - async [ResourceCommand.TYPES.DOCUMENT_EVENT]({ - targetCommand, - targetFront, - onAvailable, - }) { + async [ResourceCommand.TYPES.DOCUMENT_EVENT]({ targetFront, onAvailable }) { // DocumentEventsListener of webconsole handles only top level document. if (!targetFront.isTopLevel) { return; diff --git a/devtools/shared/commands/resource/tests/browser_resources_css_changes.js b/devtools/shared/commands/resource/tests/browser_resources_css_changes.js index 22b11a8186..e116dbceb8 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_css_changes.js +++ b/devtools/shared/commands/resource/tests/browser_resources_css_changes.js @@ -132,7 +132,7 @@ async function setProperty(rule, index, property, value) { await modifications.apply(); } -async function renameProperty(rule, index, oldName, newName, value) { +async function renameProperty(rule, index, oldName, newName) { const modifications = rule.startModifyingProperties({ isKnown: true }); modifications.renameProperty(index, oldName, newName); await modifications.apply(); diff --git a/devtools/shared/commands/resource/tests/browser_resources_css_registered_properties.js b/devtools/shared/commands/resource/tests/browser_resources_css_registered_properties.js index 1429b55167..b39d4419b1 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_css_registered_properties.js +++ b/devtools/shared/commands/resource/tests/browser_resources_css_registered_properties.js @@ -74,7 +74,7 @@ add_task(async function () { onAvailable, }); await waitFor(() => targets.length === 2); - const [topLevelTarget, iframeTarget] = targets.sort((a, b) => + const [topLevelTarget, iframeTarget] = targets.sort((a, _) => a.isTopLevel ? -1 : 1 ); diff --git a/devtools/shared/commands/resource/tests/browser_resources_network_events.js b/devtools/shared/commands/resource/tests/browser_resources_network_events.js index da355fd023..dd8211b478 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_network_events.js +++ b/devtools/shared/commands/resource/tests/browser_resources_network_events.js @@ -128,7 +128,7 @@ add_task(async function testCanceledRequest() { // from the parent process is much more reliable. const observer = { QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), - observe(subject, topic, data) { + observe(subject) { subject = subject.QueryInterface(Ci.nsIHttpChannel); if (subject.URI.spec == requestUrl) { subject.cancel(Cr.NS_BINDING_ABORTED); diff --git a/devtools/shared/commands/resource/tests/browser_resources_target_resources_race.js b/devtools/shared/commands/resource/tests/browser_resources_target_resources_race.js index 557d14380a..c319e3b9e2 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_target_resources_race.js +++ b/devtools/shared/commands/resource/tests/browser_resources_target_resources_race.js @@ -29,7 +29,7 @@ add_task(async function () { // Empty onAvailable callback for CSS MESSAGES, we only want to check that // the second resource we watch correctly provides existing resources. - const onCssMessageAvailable = resources => {}; + const onCssMessageAvailable = () => {}; // First call to watchResources. // We do not await on `watchPromise1` here, in order to simulate simultaneous diff --git a/devtools/shared/commands/resource/tests/browser_resources_thread_states.js b/devtools/shared/commands/resource/tests/browser_resources_thread_states.js index f915bb14d0..f9d49e227a 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_thread_states.js +++ b/devtools/shared/commands/resource/tests/browser_resources_thread_states.js @@ -30,6 +30,9 @@ add_task(async function () { // Check debugger statement for (remote) iframes await checkDebuggerStatementInIframes(); + + // Check the behavior of THREAD_STATE against a multiprocess usecase + await testMultiprocessThreadState(); }); async function checkBreakpointBeforeWatchResources() { @@ -507,6 +510,85 @@ async function checkDebuggerStatementInIframes() { await client.close(); } +async function testMultiprocessThreadState() { + // Ensure debugging the content processes and the tab + await pushPref("devtools.browsertoolbox.scope", "everything"); + + const { client, resourceCommand, targetCommand } = + await initMultiProcessResourceCommand(); + + info("Call watchResources"); + const availableResources = []; + await resourceCommand.watchResources([resourceCommand.TYPES.SOURCE], { + onAvailable() {}, + }); + await resourceCommand.watchResources([resourceCommand.TYPES.THREAD_STATE], { + onAvailable: resources => availableResources.push(...resources), + }); + + is( + availableResources.length, + 0, + "Got no THREAD_STATE when calling watchResources" + ); + + const tab = await addTab(BREAKPOINT_TEST_URL); + + info("Run the 'debugger' statement"); + // Note that we do not wait for the resolution of spawn as it will be paused + const onResumed = ContentTask.spawn(tab.linkedBrowser, null, () => { + content.window.wrappedJSObject.runDebuggerStatement(); + }); + + await waitFor( + () => availableResources.length == 1, + "Got the THREAD_STATE related to the debugger statement" + ); + const threadState = availableResources.pop(); + ok(threadState.targetFront.targetType, "process"); + ok(threadState.targetFront.threadFront.state, "paused"); + + assertPausedResource(threadState, { + state: "paused", + why: { + type: "debuggerStatement", + }, + frame: { + type: "call", + asyncCause: null, + state: "on-stack", + // this: object actor's form referring to `this` variable + displayName: "runDebuggerStatement", + // arguments: [] + where: { + line: 17, + column: 6, + }, + }, + }); + + await threadState.targetFront.threadFront.resume(); + + await waitFor( + () => availableResources.length == 1, + "Wait until we receive the resumed event" + ); + + const resumed = availableResources.pop(); + + assertResumedResource(resumed); + + // This is an important check, which verify that no unexpected pause happens. + // We might spawn a Thread Actor for the WindowGlobal target, which might pause the thread a second time, + // whereas we only expect the ContentProcess target actor to pause on all JS files of the related content process. + info("Wait for the content page thread to resume its execution"); + await onResumed; + is(availableResources.length, 0, "There should be no other pause"); + + targetCommand.destroy(); + await client.close(); +} + async function assertPausedResource(resource, expected) { is( resource.resourceType, diff --git a/devtools/shared/commands/resource/tests/sse_frontend.html b/devtools/shared/commands/resource/tests/sse_frontend.html index 3bdddbc5bc..359aad2215 100644 --- a/devtools/shared/commands/resource/tests/sse_frontend.html +++ b/devtools/shared/commands/resource/tests/sse_frontend.html @@ -18,7 +18,7 @@ function openConnection() { return new Promise(resolve => { const es = new EventSource("sse_backend.sjs"); - es.onmessage = function (e) { + es.onmessage = function () { es.close(); resolve(); }; diff --git a/devtools/shared/commands/resource/tests/sse_frontend_iframe.html b/devtools/shared/commands/resource/tests/sse_frontend_iframe.html index 477dca013d..1fe894cccc 100644 --- a/devtools/shared/commands/resource/tests/sse_frontend_iframe.html +++ b/devtools/shared/commands/resource/tests/sse_frontend_iframe.html @@ -18,7 +18,7 @@ function openConnection() { return new Promise(resolve => { const es = new EventSource("sse_backend.sjs"); - es.onmessage = function (e) { + es.onmessage = function () { es.close(); resolve(); }; diff --git a/devtools/shared/commands/resource/tests/test_service_worker.js b/devtools/shared/commands/resource/tests/test_service_worker.js index aabc3fda0f..0ed8942239 100644 --- a/devtools/shared/commands/resource/tests/test_service_worker.js +++ b/devtools/shared/commands/resource/tests/test_service_worker.js @@ -6,6 +6,6 @@ // We don't need any computation in the worker, // but at least register a fetch listener so that // we force instantiating the SW when loading the page. -self.onfetch = function (event) { +self.onfetch = function () { // do nothing. }; diff --git a/devtools/shared/commands/script/tests/browser_script_command_execute_basic.js b/devtools/shared/commands/script/tests/browser_script_command_execute_basic.js index e63f55a338..f5efa6ac30 100644 --- a/devtools/shared/commands/script/tests/browser_script_command_execute_basic.js +++ b/devtools/shared/commands/script/tests/browser_script_command_execute_basic.js @@ -75,6 +75,11 @@ add_task(async () => { function testFunc() {} var testLocale = new Intl.Locale("de-latn-de-u-ca-gregory-co-phonebk-hc-h23-kf-true-kn-false-nu-latn"); + + var testFormData = new FormData(); + var testHeaders = new Headers(); + var testURLSearchParams = new URLSearchParams(); + var testReadableStream = new ReadableStream(); </script> <body id="body1" class="class2"><h1>Body text</h1></body> </html>`); @@ -97,6 +102,7 @@ add_task(async () => { await doEagerEvalESGetters(commands); await doEagerEvalDOMGetters(commands); await doEagerEvalOtherNativeGetters(commands); + await doEagerEvalDOMMethods(commands); await doEagerEvalAsyncFunctions(commands); await commands.destroy(); @@ -1001,6 +1007,53 @@ async function doEagerEvalOtherNativeGetters(commands) { } } +async function doEagerEvalDOMMethods(commands) { + // The following "values" methods share single native function with different + // JitInfo, while ReadableStream's "values" isn't side-effect free. + + const testDataAllowed = [ + [`testFormData.values().constructor.name`, "Object"], + [`testHeaders.values().constructor.name`, "Object"], + [`testURLSearchParams.values().constructor.name`, "Object"], + ]; + + for (const [code, expectedResult] of testDataAllowed) { + const response = await commands.scriptCommand.execute(code, { + eager: true, + }); + checkObject( + response, + { + input: code, + result: expectedResult, + }, + code + ); + + ok(!response.exception, "no eval exception"); + ok(!response.helperResult, "no helper result"); + } + + const testDataDisallowed = ["testReadableStream.values()"]; + + for (const code of testDataDisallowed) { + const response = await commands.scriptCommand.execute(code, { + eager: true, + }); + checkObject( + response, + { + input: code, + result: { type: "undefined" }, + }, + code + ); + + ok(!response.exception, "no eval exception"); + ok(!response.helperResult, "no helper result"); + } +} + async function doEagerEvalAsyncFunctions(commands) { // [code, expectedResult] const testData = [["typeof testAsync()", "object"]]; diff --git a/devtools/shared/commands/target/actions/targets.js b/devtools/shared/commands/target/actions/targets.js index 577e5fedd3..8acd411866 100644 --- a/devtools/shared/commands/target/actions/targets.js +++ b/devtools/shared/commands/target/actions/targets.js @@ -16,7 +16,7 @@ function unregisterTarget(targetFront) { * @param {String} targetActorID: The actorID of the target we want to select. */ function selectTarget(targetActorID) { - return function ({ dispatch, getState }) { + return function ({ dispatch }) { dispatch({ type: "SELECT_TARGET", targetActorID }); }; } diff --git a/devtools/shared/commands/target/tests/browser_target_command_bfcache.js b/devtools/shared/commands/target/tests/browser_target_command_bfcache.js index 598e9c550b..c5ce76848e 100644 --- a/devtools/shared/commands/target/tests/browser_target_command_bfcache.js +++ b/devtools/shared/commands/target/tests/browser_target_command_bfcache.js @@ -236,7 +236,7 @@ async function testTopLevelNavigations(bfcacheInParent) { await commands.destroy(); } -async function testTopLevelNavigationsOnDocumentWithIframe(bfcacheInParent) { +async function testTopLevelNavigationsOnDocumentWithIframe() { info(" # Test TOP LEVEL navigations on document with iframe"); // Create a TargetCommand for a given test tab const tab = diff --git a/devtools/shared/commands/target/tests/browser_target_command_frames.js b/devtools/shared/commands/target/tests/browser_target_command_frames.js index 6aa0655b64..5f4e633d11 100644 --- a/devtools/shared/commands/target/tests/browser_target_command_frames.js +++ b/devtools/shared/commands/target/tests/browser_target_command_frames.js @@ -366,7 +366,7 @@ async function testBrowserFrames() { await commands.destroy(); } -async function testTabFrames(mainRoot) { +async function testTabFrames() { info("Test TargetCommand against frames via a tab target"); // Create a TargetCommand for a given test tab diff --git a/devtools/shared/commands/target/tests/browser_target_command_processes.js b/devtools/shared/commands/target/tests/browser_target_command_processes.js index d4f57ae036..9b55b34027 100644 --- a/devtools/shared/commands/target/tests/browser_target_command_processes.js +++ b/devtools/shared/commands/target/tests/browser_target_command_processes.js @@ -178,11 +178,13 @@ async function testProcesses(targetCommand, target) { onAvailable: onAvailable2, }); }); + info("open new tab in new process"); const tab1 = await BrowserTestUtils.openNewForegroundTab({ gBrowser, url: TEST_URL, forceNewProcess: true, }); + info("wait for process target to be created"); const createdTarget = await onProcessCreated; // For some reason, creating a new tab purges processes created from previous tests // so it is not reasonable to assert the size of `targets` as it may be lower than expected. diff --git a/devtools/shared/commands/target/tests/browser_target_command_scope_flag.js b/devtools/shared/commands/target/tests/browser_target_command_scope_flag.js index 65d9e9a622..0ceaaf39ee 100644 --- a/devtools/shared/commands/target/tests/browser_target_command_scope_flag.js +++ b/devtools/shared/commands/target/tests/browser_target_command_scope_flag.js @@ -52,6 +52,25 @@ add_task(async function () { forceNewProcess: true, }); + // Verify that only PROCESS and top target have their thread actor attached. + // We especially care about having the FRAME targets to not be attached, + // otherwise we would have two thread actor debugging the same thread + // with the PROCESS target already debugging all FRAME documents. + for (const target of targets) { + const threadFront = await target.getFront("thread"); + const isAttached = await threadFront.isAttached(); + if (target.targetType == TYPES.PROCESS) { + ok(isAttached, "All process targets are attached"); + } else if (target.isTopLevel) { + ok(isAttached, "The top level target is attached"); + } else { + ok( + !isAttached, + "The frame targets should not be attached in multiprocess mode" + ); + } + } + const newTabProcessID = gBrowser.selectedTab.linkedBrowser.browsingContext.currentWindowGlobal .osPid; diff --git a/devtools/shared/commands/target/tests/test_service_worker.js b/devtools/shared/commands/target/tests/test_service_worker.js index aabc3fda0f..0ed8942239 100644 --- a/devtools/shared/commands/target/tests/test_service_worker.js +++ b/devtools/shared/commands/target/tests/test_service_worker.js @@ -6,6 +6,6 @@ // We don't need any computation in the worker, // but at least register a fetch listener so that // we force instantiating the SW when loading the page. -self.onfetch = function (event) { +self.onfetch = function () { // do nothing. }; diff --git a/devtools/shared/commands/thread-configuration/thread-configuration-command.js b/devtools/shared/commands/thread-configuration/thread-configuration-command.js index 0db1c2a285..8896cb17bc 100644 --- a/devtools/shared/commands/thread-configuration/thread-configuration-command.js +++ b/devtools/shared/commands/thread-configuration/thread-configuration-command.js @@ -32,7 +32,7 @@ class ThreadConfigurationCommand { // the thread configuration actor. const filteredConfiguration = Object.fromEntries( Object.entries(configuration).filter( - ([key, value]) => !["breakpoints", "eventBreakpoints"].includes(key) + ([key]) => !["breakpoints", "eventBreakpoints"].includes(key) ) ); diff --git a/devtools/shared/commands/tracer/tracer-command.js b/devtools/shared/commands/tracer/tracer-command.js index f512c15d9e..80c461a199 100644 --- a/devtools/shared/commands/tracer/tracer-command.js +++ b/devtools/shared/commands/tracer/tracer-command.js @@ -6,13 +6,11 @@ class TracerCommand { constructor({ commands }) { - this.#targetCommand = commands.targetCommand; this.#targetConfigurationCommand = commands.targetConfigurationCommand; this.#resourceCommand = commands.resourceCommand; } #resourceCommand; - #targetCommand; #targetConfigurationCommand; #isTracing = false; |