browser_document_rdp_basics.js (5774B)
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("resources-available-array"); 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 { type, array } = await onConsoleMessages; 123 124 // The resources are encapsulated into a RDP event packet, with an "array" attribute 125 is(type, "resources-available-array"); 126 is( 127 array.length, 128 1, 129 "The top array has only one array, as only one resourceType is notified" 130 ); 131 // This array attribute is an array of arrays with two elements each. 132 // These two elements are a resourceType string and a resources array. 133 is(array[0].length, 2); 134 const [resourceType, resources] = array[0]; 135 is(resourceType, "console-message"); 136 is(resources.length, 1, "Received only one console-message resource"); 137 // Note that resources-available-array comes with a "array" attribute which is an array of resources 138 // which may contain various resource types. 139 is(resources[0].arguments[0], "42"); 140 141 await client.close(); 142 });