diff --git a/shell/common/extensions/api/tabs.json b/shell/common/extensions/api/tabs.json
index 354fa2487b87..02116ec13cbb 100644
--- a/shell/common/extensions/api/tabs.json
+++ b/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 Content Script Messaging.",
+ "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 frame identified by frameId
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",
diff --git a/spec-main/extensions-spec.ts b/spec-main/extensions-spec.ts
index 236556e07ebc..77ff3d4f562c 100644
--- a/spec-main/extensions-spec.ts
+++ b/spec-main/extensions-spec.ts
@@ -186,6 +186,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'))
diff --git a/spec-main/fixtures/extensions/chrome-api/background.js b/spec-main/fixtures/extensions/chrome-api/background.js
index 06d2a9d77796..e546490ce39b 100644
--- a/spec-main/fixtures/extensions/chrome-api/background.js
+++ b/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
diff --git a/spec-main/fixtures/extensions/chrome-api/main.js b/spec-main/fixtures/extensions/chrome-api/main.js
index ee7ec1f2b91c..3de786d22c2e 100644
--- a/spec-main/fixtures/extensions/chrome-api/main.js
+++ b/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] })
}
}