Skip to content

Commit 689594b

Browse files
committed
Bug 1836856 - [devtools] Document basic usages of RDP via a simple mochitest. r=devtools-reviewers,bomsy
Try to document navigating throught the Root, Watcher, Target and Console actors to listen for console messages and evalute some JS code. Differential Revision: https://phabricator.services.mozilla.com/D180981
1 parent 1cc2d74 commit 689594b

File tree

3 files changed

+234
-0
lines changed

3 files changed

+234
-0
lines changed

devtools/server/tests/browser/browser.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,5 @@ https_first_disabled = true
149149
[browser_style_utils_getFontPreviewData.js]
150150
[browser_styles_getRuleText.js]
151151
[browser_stylesheets_getTextEmpty.js]
152+
[browser_document_devtools_basics.js]
153+
[browser_document_rdp_basics.js]
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* Any copyright is dedicated to the Public Domain.
2+
* http://creativecommons.org/publicdomain/zero/1.0/ */
3+
4+
/**
5+
* Document the basics of DevTools backend via Fronts in a test.
6+
*/
7+
8+
"use strict";
9+
10+
const TEST_URL = "data:text/html,new-tab";
11+
12+
add_task(async () => {
13+
// Allow logging all RDP packets
14+
await pushPref("devtools.debugger.log", true);
15+
// Really all of them
16+
await pushPref("devtools.debugger.log.verbose", true);
17+
18+
// Instantiate a DevTools server
19+
DevToolsServer.init();
20+
DevToolsServer.registerAllActors();
21+
22+
// Instantiate a client connected to this server
23+
const transport = DevToolsServer.connectPipe();
24+
const client = new DevToolsClient(transport);
25+
26+
// This will trigger some handshake with the server
27+
await client.connect();
28+
29+
// You need to call listTabs once to retrieve the existing list of Tab Descriptor actors...
30+
const tabs = await client.mainRoot.listTabs();
31+
32+
// ... which will let you receive the 'tabListChanged' event.
33+
// This is an empty RDP packet, you need to re-call listTabs to get the full new updated list of actors.
34+
const onTabListUpdated = client.mainRoot.once("tabListChanged");
35+
36+
// Open a new tab.
37+
await BrowserTestUtils.openNewForegroundTab({
38+
gBrowser,
39+
url: TEST_URL,
40+
});
41+
42+
await onTabListUpdated;
43+
44+
// The new list of Tab descriptors should contain the newly opened tab
45+
const newTabs = await client.mainRoot.listTabs();
46+
is(newTabs.length, tabs.length + 1);
47+
48+
const tabDescriptorActor = newTabs.pop();
49+
is(tabDescriptorActor.url, TEST_URL);
50+
51+
// Query the Tab Descriptor actor to retrieve its related Watcher actor.
52+
// Each Descriptor actor has a dedicated watcher which will be scoped to the context of the descriptor.
53+
// Here the watcher will focus on the related tab.
54+
const watcherActor = await tabDescriptorActor.getWatcher();
55+
56+
// The call to Watcher Actor's watchTargets will emit target-available-form RDP events.
57+
// One per available target. It will emit one for each immediatly available target,
58+
// but also for any available later. That, until you call unwatchTarget method.
59+
//
60+
// Here I'm listening to "target-available" to get a Front instance, which helps call RDP methods.
61+
// But this isn't an RDP event. This is a frontend-only thing.
62+
const onTopTargetAvailable = watcherActor.once("target-available");
63+
64+
// watchTargets accepts "frame", "process" and "worker"
65+
// When debugging a web page you want to listen to frame and worker targets.
66+
// "frame" would better be named "WindowGlobal" as it will notify you about all the WindowGlobal of the page.
67+
// Each top level documents and any iframe documents will have a related WindowGlobal,
68+
// if any of these documents navigate, a new WindowGlobal will be instantiated.
69+
// If you care about workers, listen to worker targets as well.
70+
await watcherActor.watchTargets("frame");
71+
72+
// This is a trivial example so we have a unique WindowGlobal target for the top level document
73+
const topTarget = await onTopTargetAvailable;
74+
is(topTarget.url, TEST_URL);
75+
76+
// Similarly to watchTarget, the next call to watchResources will emit new resources right away as well as later.
77+
const onConsoleMessages = topTarget.once("resource-available-form");
78+
79+
// If you want to observe anything, you have to use Watcher Actor's watchrResources API.
80+
// The list of all available resources is here:
81+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/resources/index.js#9
82+
// And you might have a look at each ResourceWatcher subclass to learn more about the fields exposed by each resource type:
83+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/resources
84+
await watcherActor.watchResources(["console-message"]);
85+
86+
// You may use many useful actors on each target actor, like console, thread, ...
87+
// You can get the full list of available actors in:
88+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/utils/actor-registry.js#176
89+
// And then look into the mentioned path for implementation.
90+
const webConsoleActor = await topTarget.getFront("console");
91+
92+
// Call the Console API in order to force emitting a console-message resource
93+
await webConsoleActor.evaluateJSAsync({ text: "console.log('42')" });
94+
95+
// Wait for the related console-message resource
96+
const resources = await onConsoleMessages;
97+
98+
// Note that resource-available-form comes with a "resources" attribute which is an array of resources
99+
// which may contain various resource types.
100+
is(resources[0].message.arguments[0], "42");
101+
102+
await client.close();
103+
});
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* Any copyright is dedicated to the Public Domain.
2+
* http://creativecommons.org/publicdomain/zero/1.0/ */
3+
4+
/**
5+
* Document the basics of RDP packets via a test.
6+
*/
7+
8+
"use strict";
9+
10+
const TEST_URL = "data:text/html,new-tab";
11+
12+
add_task(async () => {
13+
// Allow logging all RDP packets
14+
await pushPref("devtools.debugger.log", true);
15+
// Really all of them
16+
await pushPref("devtools.debugger.log.verbose", true);
17+
18+
// Instantiate a DevTools server
19+
DevToolsServer.init();
20+
DevToolsServer.registerAllActors();
21+
22+
// Instantiate a client connected to this server
23+
const transport = DevToolsServer.connectPipe();
24+
const client = new DevToolsClient(transport);
25+
26+
// This will trigger some handshake with the server
27+
await client.connect();
28+
29+
// Ignore this gross hack, this is to be able to emit raw RDP packet via client.request
30+
// (a Front is instantiated by DevToolsClient which would be confused with us sending
31+
// RDP packets for the Root actor)
32+
client.mainRoot.destroy();
33+
34+
// You need to call listTabs once to retrieve the existing list of Tab Descriptor actors...
35+
const { tabs } = await client.request({ to: "root", type: "listTabs" });
36+
37+
// ... which will let you receive the 'tabListChanged' event.
38+
// This is an empty RDP packet, you need to re-call listTabs to get the full new updated list of actors.
39+
const onTabListUpdated = client.once("tabListChanged");
40+
41+
// Open a new tab.
42+
await BrowserTestUtils.openNewForegroundTab({
43+
gBrowser,
44+
url: TEST_URL,
45+
});
46+
47+
await onTabListUpdated;
48+
49+
// The new list of Tab descriptors should contain the newly opened tab
50+
const { tabs: newTabs } = await client.request({
51+
to: "root",
52+
type: "listTabs",
53+
});
54+
is(newTabs.length, tabs.length + 1);
55+
56+
const tabDescriptorActor = newTabs.pop();
57+
is(tabDescriptorActor.url, TEST_URL);
58+
59+
// Query the Tab Descriptor actor to retrieve its related Watcher actor.
60+
// Each Descriptor actor has a dedicated watcher which will be scoped to the context of the descriptor.
61+
// Here the watcher will focus on the related tab.
62+
//
63+
// You want to pass isServerTargetSwitchingEnabled set to true in order to be notified about the top level document,
64+
// as well as navigations to subsequent documents.
65+
const watcherActor = await client.request({
66+
to: tabDescriptorActor.actor,
67+
type: "getWatcher",
68+
isServerTargetSwitchingEnabled: true,
69+
});
70+
71+
// The call to Watcher Actor's watchTargets will emit target-available-form RDP events.
72+
// One per available target. It will emit one for each immediatly available target,
73+
// but also for any available later. That, until you call unwatchTarget method.
74+
const onTopTargetAvailable = client.once("target-available-form");
75+
76+
// watchTargets accepts "frame", "process" and "worker"
77+
// When debugging a web page you want to listen to frame and worker targets.
78+
// "frame" would better be named "WindowGlobal" as it will notify you about all the WindowGlobal of the page.
79+
// Each top level documents and any iframe documents will have a related WindowGlobal,
80+
// if any of these documents navigate, a new WindowGlobal will be instantiated.
81+
// If you care about workers, listen to worker targets as well.
82+
await client.request({
83+
to: watcherActor.actor,
84+
type: "watchTargets",
85+
targetType: "frame",
86+
});
87+
88+
// This is a trivial example so we have a unique WindowGlobal target for the top level document
89+
const { target: topTarget } = await onTopTargetAvailable;
90+
is(topTarget.url, TEST_URL);
91+
92+
// Similarly to watchTarget, the next call to watchResources will emit new resources right away as well as later.
93+
const onConsoleMessages = client.once("resource-available-form");
94+
95+
// If you want to observe anything, you have to use Watcher Actor's watchrResources API.
96+
// The list of all available resources is here:
97+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/resources/index.js#9
98+
// And you might have a look at each ResourceWatcher subclass to learn more about the fields exposed by each resource type:
99+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/resources
100+
await client.request({
101+
to: watcherActor.actor,
102+
type: "watchResources",
103+
resourceTypes: ["console-message"],
104+
});
105+
106+
// You may use many useful actors on each target actor, like console, thread, ...
107+
// You can get the full list of available actors in:
108+
// https://searchfox.org/mozilla-central/source/devtools/server/actors/utils/actor-registry.js#176
109+
// And then look into the mentioned path for implementation.
110+
//
111+
// The "target form" contains the list of all these actor IDs
112+
const webConsoleActorID = topTarget.consoleActor;
113+
114+
// Call the Console API in order to force emitting a console-message resource
115+
await client.request({
116+
to: webConsoleActorID,
117+
type: "evaluateJSAsync",
118+
text: "console.log('42')",
119+
});
120+
121+
// Wait for the related console-message resource
122+
const { resources } = await onConsoleMessages;
123+
124+
// Note that resource-available-form comes with a "resources" attribute which is an array of resources
125+
// which may contain various resource types.
126+
is(resources[0].message.arguments[0], "42");
127+
128+
await client.close();
129+
});

0 commit comments

Comments
 (0)