Browse Source

feat(extensions): add chrome.tabs.connect API (#22549)

* feat(extensions): add chrome.tabs.connect API

* test(extensions): verify that chrome.tabs.connect port communication works

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

+ 31 - 0
shell/common/extensions/api/tabs.json

@@ -138,6 +138,37 @@
           }
         ]
       },
+      {
+        "name": "connect",
+        "nocompile": true,
+        "type": "function",
+        "description": "Connects to the content script(s) in the specified tab. The $(ref:runtime.onConnect) event is fired in each content script running in the specified tab for the current extension. For more details, see <a href='messaging'>Content Script Messaging</a>.",
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "tabId",
+            "minimum": 0
+          },
+          {
+            "type": "object",
+            "name": "connectInfo",
+            "properties": {
+              "name": { "type": "string", "optional": true, "description": "Is passed into onConnect for content scripts that are listening for the connection event." },
+              "frameId": {
+                "type": "integer",
+                "optional": true,
+                "minimum": 0,
+                "description": "Open a port to a specific <a href='webNavigation#frame_ids'>frame</a> identified by <code>frameId</code> instead of all frames in the tab."
+              }
+            },
+            "optional": true
+          }
+        ],
+        "returns": {
+          "$ref": "runtime.Port",
+          "description": "A port that can be used to communicate with the content scripts running in the specified tab. The port's $(ref:runtime.Port) event is fired if the tab closes or does not exist. "
+        }
+      },
       {
         "name": "executeScript",
         "type": "function",

+ 16 - 0
spec-main/extensions-spec.ts

@@ -163,6 +163,22 @@ ifdescribe(process.electronBinding('features').isExtensionsEnabled())('chrome ex
       expect(response).to.equal(3)
     })
 
+    it('connect', async () => {
+      const customSession = session.fromPartition(`persist:${require('uuid').v4()}`)
+      await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-api'))
+      const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } })
+      await w.loadURL(url)
+
+      const portName = require('uuid').v4()
+      const message = { method: 'connectTab', args: [portName] }
+      w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`)
+
+      const [,, responseString] = await emittedOnce(w.webContents, 'console-message')
+      const response = responseString.split(',')
+      expect(response[0]).to.equal(portName)
+      expect(response[1]).to.equal('howdy')
+    })
+
     it('sendMessage receives the response', async function () {
       const customSession = session.fromPartition(`persist:${require('uuid').v4()}`)
       await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-api'))

+ 7 - 0
spec-main/fixtures/extensions/chrome-api/background.js

@@ -16,6 +16,13 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
       chrome.tabs.executeScript(tabId, { code }, ([result]) => sendResponse(result))
       break
     }
+
+    case 'connectTab': {
+      const [name] = args
+      const port = chrome.tabs.connect(tabId, { name })
+      port.postMessage('howdy')
+      break
+    }
   }
   // Respond asynchronously
   return true

+ 8 - 0
spec-main/fixtures/extensions/chrome-api/main.js

@@ -29,6 +29,14 @@ const testMap = {
     chrome.runtime.sendMessage({ method: 'executeScript', args: [code] }, response => {
       console.log(JSON.stringify(response))
     })
+  },
+  connectTab (name) {
+    chrome.runtime.onConnect.addListener(port => {
+      port.onMessage.addListener(message => {
+        console.log([port.name, message].join())
+      })
+    })
+    chrome.runtime.sendMessage({ method: 'connectTab', args: [name] })
   }
 }