Browse Source

feat: add webContents.fromDevToolsTargetId() (#30732)

* feat: add webContents.fromDevToolsTargetId()

* refactor: avoid using FromOrCreate

Co-authored-by: samuelmaddock <[email protected]>
trop[bot] 3 years ago
parent
commit
3cdb74e9bd

+ 20 - 0
docs/api/web-contents.md

@@ -45,6 +45,26 @@ returns `null`.
 Returns `WebContents` | undefined - A WebContents instance with the given ID, or
 `undefined` if there is no WebContents associated with the given ID.
 
+### `webContents.fromDevToolsTargetId(targetId)`
+
+* `targetId` String - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance.
+
+Returns `WebContents` | undefined - A WebContents instance with the given TargetID, or
+`undefined` if there is no WebContents associated with the given TargetID.
+
+When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/),
+it can be useful to lookup a WebContents instance based on its assigned TargetID.
+
+```js
+async function lookupTargetId (browserWindow) {
+  const wc = browserWindow.webContents
+  await wc.debugger.attach('1.3')
+  const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo')
+  const { targetId } = targetInfo
+  const targetWebContents = await webContents.fromDevToolsTargetId(targetId)
+}
+```
+
 ## Class: WebContents
 
 > Render and control the contents of a BrowserWindow instance.

+ 4 - 0
lib/browser/api/web-contents.ts

@@ -769,6 +769,10 @@ export function fromId (id: string) {
   return binding.fromId(id);
 }
 
+export function fromDevToolsTargetId (targetId: string) {
+  return binding.fromDevToolsTargetId(targetId);
+}
+
 export function getFocusedWebContents () {
   let focused = null;
   for (const contents of binding.getAllWebContents()) {

+ 11 - 0
shell/browser/api/electron_api_web_contents.cc

@@ -3909,6 +3909,16 @@ gin::Handle<WebContents> WebContentsFromID(v8::Isolate* isolate, int32_t id) {
                   : gin::Handle<WebContents>();
 }
 
+gin::Handle<WebContents> WebContentsFromDevToolsTargetID(
+    v8::Isolate* isolate,
+    std::string target_id) {
+  auto agent_host = content::DevToolsAgentHost::GetForId(target_id);
+  WebContents* contents =
+      agent_host ? WebContents::From(agent_host->GetWebContents()) : nullptr;
+  return contents ? gin::CreateHandle(isolate, contents)
+                  : gin::Handle<WebContents>();
+}
+
 std::vector<gin::Handle<WebContents>> GetAllWebContentsAsV8(
     v8::Isolate* isolate) {
   std::vector<gin::Handle<WebContents>> list;
@@ -3927,6 +3937,7 @@ void Initialize(v8::Local<v8::Object> exports,
   gin_helper::Dictionary dict(isolate, exports);
   dict.Set("WebContents", WebContents::GetConstructor(context));
   dict.SetMethod("fromId", &WebContentsFromID);
+  dict.SetMethod("fromDevToolsTargetId", &WebContentsFromDevToolsTargetID);
   dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
 }
 

+ 18 - 0
spec-main/api-web-contents-spec.ts

@@ -47,6 +47,24 @@ describe('webContents module', () => {
     });
   });
 
+  describe('fromDevToolsTargetId()', () => {
+    it('returns WebContents for attached DevTools target', async () => {
+      const w = new BrowserWindow({ show: false });
+      await w.loadURL('about:blank');
+      try {
+        await w.webContents.debugger.attach('1.3');
+        const { targetInfo } = await w.webContents.debugger.sendCommand('Target.getTargetInfo');
+        expect(webContents.fromDevToolsTargetId(targetInfo.targetId)).to.equal(w.webContents);
+      } finally {
+        await w.webContents.debugger.detach();
+      }
+    });
+
+    it('returns undefined for an unknown id', () => {
+      expect(webContents.fromDevToolsTargetId('nope')).to.be.undefined();
+    });
+  });
+
   describe('will-prevent-unload event', function () {
     afterEach(closeAllWindows);
     it('does not emit if beforeunload returns undefined in a BrowserWindow', async () => {