Browse Source

feat: allow inspection of specific shared workers (#20389)

Milan Burda 5 years ago
parent
commit
2f03d393c3

+ 4 - 0
docs/api/structures/shared-worker-info.md

@@ -0,0 +1,4 @@
+# SharedWorkerInfo Object
+
+* `id` String - The unique id of the shared worker.
+* `url` String - The url of the shared worker.

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

@@ -1460,6 +1460,16 @@ Starts inspecting element at position (`x`, `y`).
 
 Opens the developer tools for the shared worker context.
 
+#### `contents.inspectSharedWorkerById(workerId)`
+
+* `workerId` String
+
+Inspects the shared worker based on its ID.
+
+#### `contents.getAllSharedWorkers()`
+
+Returns [`SharedWorkerInfo[]`](structures/shared-worker-info.md) - Information about all Shared Workers.
+
 #### `contents.inspectServiceWorker()`
 
 Opens the developer tools for the service worker context.

+ 1 - 0
filenames.auto.gni

@@ -110,6 +110,7 @@ auto_filenames = {
     "docs/api/structures/remove-password.md",
     "docs/api/structures/scrubber-item.md",
     "docs/api/structures/segmented-control-segment.md",
+    "docs/api/structures/shared-worker-info.md",
     "docs/api/structures/shortcut-details.md",
     "docs/api/structures/size.md",
     "docs/api/structures/stream-protocol-response.md",

+ 54 - 0
shell/browser/api/atom_api_web_contents.cc

@@ -8,6 +8,7 @@
 #include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/message_loop/message_loop_current.h"
 #include "base/no_destructor.h"
@@ -298,6 +299,18 @@ struct Converter<electron::api::WebContents::Type> {
   }
 };
 
+template <>
+struct Converter<scoped_refptr<content::DevToolsAgentHost>> {
+  static v8::Local<v8::Value> ToV8(
+      v8::Isolate* isolate,
+      const scoped_refptr<content::DevToolsAgentHost>& val) {
+    mate::Dictionary dict(isolate, v8::Object::New(isolate));
+    dict.Set("id", val->GetId());
+    dict.Set("url", val->GetURL().spec());
+    return dict.GetHandle();
+  }
+};
+
 }  // namespace mate
 
 namespace electron {
@@ -1569,6 +1582,44 @@ void WebContents::InspectElement(int x, int y) {
   managed_web_contents()->InspectElement(x, y);
 }
 
+void WebContents::InspectSharedWorkerById(const std::string& workerId) {
+  if (type_ == Type::REMOTE)
+    return;
+
+  if (!enable_devtools_)
+    return;
+
+  for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
+    if (agent_host->GetType() ==
+        content::DevToolsAgentHost::kTypeSharedWorker) {
+      if (agent_host->GetId() == workerId) {
+        OpenDevTools(nullptr);
+        managed_web_contents()->AttachTo(agent_host);
+        break;
+      }
+    }
+  }
+}
+
+std::vector<scoped_refptr<content::DevToolsAgentHost>>
+WebContents::GetAllSharedWorkers() {
+  std::vector<scoped_refptr<content::DevToolsAgentHost>> shared_workers;
+
+  if (type_ == Type::REMOTE)
+    return shared_workers;
+
+  if (!enable_devtools_)
+    return shared_workers;
+
+  for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
+    if (agent_host->GetType() ==
+        content::DevToolsAgentHost::kTypeSharedWorker) {
+      shared_workers.push_back(agent_host);
+    }
+  }
+  return shared_workers;
+}
+
 void WebContents::InspectSharedWorker() {
   if (type_ == Type::REMOTE)
     return;
@@ -2493,6 +2544,9 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
       .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
       .SetMethod("inspectSharedWorker", &WebContents::InspectSharedWorker)
+      .SetMethod("inspectSharedWorkerById",
+                 &WebContents::InspectSharedWorkerById)
+      .SetMethod("getAllSharedWorkers", &WebContents::GetAllSharedWorkers)
 #if BUILDFLAG(ENABLE_PRINTING)
       .SetMethod("_print", &WebContents::Print)
       .SetMethod("_getPrinters", &WebContents::GetPrinterList)

+ 3 - 0
shell/browser/api/atom_api_web_contents.h

@@ -13,6 +13,7 @@
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 #include "content/common/cursors/webcursor.h"
+#include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/keyboard_event_processing_result.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
@@ -171,6 +172,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
   void DisableDeviceEmulation();
   void InspectElement(int x, int y);
   void InspectSharedWorker();
+  void InspectSharedWorkerById(const std::string& workerId);
+  std::vector<scoped_refptr<content::DevToolsAgentHost>> GetAllSharedWorkers();
   void InspectServiceWorker();
   void SetIgnoreMenuShortcuts(bool ignore);
   void SetAudioMuted(bool muted);

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

@@ -1479,4 +1479,40 @@ describe('webContents module', () => {
       expect(val).to.equal('test value', 'value should eventually become the pasted value')
     })
   })
+
+  describe('Shared Workers', () => {
+    afterEach(closeAllWindows)
+
+    it('can get multiple shared workers', async () => {
+      const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
+
+      const ready = emittedOnce(ipcMain, 'ready')
+      w.loadFile(path.join(fixturesPath, 'api', 'shared-worker', 'shared-worker.html'))
+      await ready
+
+      const sharedWorkers = w.webContents.getAllSharedWorkers()
+
+      expect(sharedWorkers).to.have.lengthOf(2)
+      expect(sharedWorkers[0].url).to.contain('shared-worker')
+      expect(sharedWorkers[1].url).to.contain('shared-worker')
+    })
+
+    it('can inspect a specific shared worker', async () => {
+      const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
+
+      const ready = emittedOnce(ipcMain, 'ready')
+      w.loadFile(path.join(fixturesPath, 'api', 'shared-worker', 'shared-worker.html'))
+      await ready
+
+      const sharedWorkers = w.webContents.getAllSharedWorkers()
+
+      const devtoolsOpened = emittedOnce(w.webContents, 'devtools-opened')
+      w.webContents.inspectSharedWorkerById(sharedWorkers[0].id)
+      await devtoolsOpened
+
+      const devtoolsClosed = emittedOnce(w.webContents, 'devtools-closed')
+      w.webContents.closeDevTools()
+      await devtoolsClosed
+    })
+  })
 })

+ 25 - 0
spec/fixtures/api/shared-worker/shared-worker.html

@@ -0,0 +1,25 @@
+<html>
+<body>
+<script>
+const { ipcRenderer } = require('electron')
+
+const worker1 = new SharedWorker('./shared-worker1.js')
+const worker2 = new SharedWorker('./shared-worker2.js')
+
+worker1.port.start()
+worker2.port.start()
+
+const promise1 = new Promise(resolve => {
+  worker1.port.onmessage = resolve
+})
+
+const promise2 = new Promise(resolve => {
+  worker2.port.onmessage = resolve
+})
+
+Promise.all([promise1, promise2]).then(() => {
+  ipcRenderer.send('ready')
+})
+</script>
+</body>
+</html>

+ 4 - 0
spec/fixtures/api/shared-worker/shared-worker1.js

@@ -0,0 +1,4 @@
+self.onconnect = function (e) {
+  const port = e.ports[0]
+  port.postMessage('ready')
+}

+ 4 - 0
spec/fixtures/api/shared-worker/shared-worker2.js

@@ -0,0 +1,4 @@
+self.onconnect = function (e) {
+  const port = e.ports[0]
+  port.postMessage('ready')
+}