Files
firefox/devtools/server/tests/xpcshell/test_addon_debugging_connect.js
T
Alexandre Poirot 26d9f9bb91 Bug 1713093 - [devtools] Remove TargetMixin.attachThread. r=devtools-reviewers,nchevobbe
This code was only used for workers targets, which weren't passing breakpoints
from the server side via "sessionData" concept.
Instead, we were still relying on the frontend to pass them and only after that
manually requesting the thread to resume its execution.

Now, there is still a notion of "attach" around the thread actor.
While all the targets are immediately instantiating their related thread actor,
the thread actor isn't active by default.
It becomes active as soon as:
* SOURCE or THREAD_STATE resource is watched
* breakpoints are set via session data (breakpoint list actor)
* thread configuration are set via session data (thread configuration actor)
I had to do one of these things in order to keep test from working.
In the production code, we do most of these things by default on the toolbox startup.
We could revise this behavior by:
* always attaching the thread actor, but it may start pausing unexpectedly in some tests.
* decouple sources from breakpoints within the thread actor, so that watching for sources doesn't necessarily "attach" the thread actor and activate breakpoints/debugger statements.
* have a new thread configuration to explicitly enable the thread actor pausing features.

I'm often using thread configuration to enable pausing in tests.
This required to improve xpcshell test helpers to be able to use Watcher/Commands.

About browser_target_command_bfcache.js, the DevTools code is now so quick that the
back/forward requests at done too quickly one after the other and fail actually moving to
the other document.

Differential Revision: https://phabricator.services.mozilla.com/D166321
2024-03-20 12:30:17 +00:00

159 lines
4.6 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { ExtensionTestUtils } = ChromeUtils.importESModule(
"resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
});
const { createAppInfo, promiseStartupManager } = AddonTestUtils;
AddonTestUtils.init(this);
createAppInfo("[email protected]", "XPCShell", "1", "42");
ExtensionTestUtils.init(this);
function watchFrameUpdates(front) {
const collected = [];
const listener = data => {
collected.push(data);
};
front.on("frameUpdate", listener);
let unsubscribe = () => {
unsubscribe = null;
front.off("frameUpdate", listener);
return collected;
};
return unsubscribe;
}
function promiseFrameUpdate(front, matcher = () => true) {
return new Promise(resolve => {
const listener = data => {
if (matcher(data)) {
resolve();
front.off("frameUpdate", listener);
}
};
front.on("frameUpdate", listener);
});
}
// Bug 1302702 - Test connect to a webextension addon
add_task(
{
// This test needs to run only when the extension are running in a separate
// child process, otherwise the thread actor would pause the main process and this
// test would get stuck.
skip_if: () => !WebExtensionPolicy.useRemoteWebExtensions,
},
async function test_webextension_addon_debugging_connect() {
await promiseStartupManager();
// Install and start a test webextension.
const extension = ExtensionTestUtils.loadExtension({
useAddonManager: "temporary",
background() {
const { browser } = this;
browser.test.log("background script executed");
// window is available in background scripts
// eslint-disable-next-line no-undef
browser.test.sendMessage("background page ready", window.location.href);
},
});
await extension.startup();
const bgPageURL = await extension.awaitMessage("background page ready");
const commands = await CommandsFactory.forAddon(extension.id);
// Connect to the target addon actor and wait for the updated list of frames.
const addonTarget = await commands.descriptorFront.getTarget();
ok(addonTarget, "Got an RDP target");
const { frames } = await addonTarget.listFrames();
const backgroundPageFrame = frames
.filter(frame => {
return (
frame.url && frame.url.endsWith("/_generated_background_page.html")
);
})
.pop();
ok(backgroundPageFrame, "Found the frame for the background page");
const threadFront = await addonTarget.getFront("thread");
ok(threadFront, "Got a threadFront for the target addon");
equal(threadFront.paused, false, "The addon threadActor isn't paused");
equal(
lazy.ExtensionParent.DebugUtils.debugBrowserPromises.size,
1,
"The expected number of debug browser has been created by the addon actor"
);
const unwatchFrameUpdates = watchFrameUpdates(addonTarget);
const promiseBgPageFrameUpdate = promiseFrameUpdate(addonTarget, data => {
return data.frames?.some(frame => frame.url === bgPageURL);
});
// Reload the addon through the RDP protocol.
await addonTarget.reload();
info("Wait background page to be fully reloaded");
await extension.awaitMessage("background page ready");
info("Wait background page frameUpdate event");
await promiseBgPageFrameUpdate;
equal(
lazy.ExtensionParent.DebugUtils.debugBrowserPromises.size,
1,
"The number of debug browser has not been changed after an addon reload"
);
const frameUpdates = unwatchFrameUpdates();
const [frameUpdate] = frameUpdates;
equal(
frameUpdates.length,
1,
"Expect 1 frameUpdate events to have been received"
);
equal(
frameUpdate.frames?.length,
1,
"Expect 1 frame in the frameUpdate event "
);
Assert.deepEqual(
{
url: frameUpdate.frames[0].url,
},
{
url: bgPageURL,
},
"Got the expected frame update when the addon background page was loaded back"
);
await commands.destroy();
// Check that if we close the debugging client without uninstalling the addon,
// the webextension debugging actor should release the debug browser.
equal(
lazy.ExtensionParent.DebugUtils.debugBrowserPromises.size,
0,
"The debug browser has been released when the RDP connection has been closed"
);
await extension.unload();
}
);