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] }) } }