diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 73d4875b99a87..b0a206cd31b8a 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -673,6 +673,26 @@ Returns: Emitted when the preload script `preloadPath` throws an unhandled exception `error`. +#### Event: 'ipc-message' + +Returns: + +* `event` Event +* `channel` String +* `...args` any[] + +Emitted when the renderer process sends an asynchronous message via `ipcRenderer.send()`. + +#### Event: 'ipc-message-sync' + +Returns: + +* `event` Event +* `channel` String +* `...args` any[] + +Emitted when the renderer process sends a synchronous message via `ipcRenderer.sendSync()`. + #### Event: 'desktop-capturer-get-sources' Returns: diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 78933e7114d15..8d9d9623309a7 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -342,17 +342,19 @@ WebContents.prototype._init = function () { this.capturePage = deprecate.promisify(this.capturePage, 2) // Dispatch IPC messages to the ipc module. - this.on('ipc-message', function (event, [channel, ...args]) { + this.on('-ipc-message', function (event, [channel, ...args]) { + this.emit('ipc-message', event, channel, ...args) ipcMain.emit(channel, event, ...args) }) - this.on('ipc-message-sync', function (event, [channel, ...args]) { + this.on('-ipc-message-sync', function (event, [channel, ...args]) { Object.defineProperty(event, 'returnValue', { set: function (value) { return event.sendReply([value]) }, get: function () {} }) + this.emit('ipc-message-sync', event, channel, ...args) ipcMain.emit(channel, event, ...args) }) diff --git a/lib/renderer/api/ipc-renderer.js b/lib/renderer/api/ipc-renderer.js index 7705f9f9ae77c..1911543e42a7c 100644 --- a/lib/renderer/api/ipc-renderer.js +++ b/lib/renderer/api/ipc-renderer.js @@ -8,11 +8,11 @@ const ipcRenderer = v8Util.getHiddenValue(global, 'ipc') const internal = false ipcRenderer.send = function (...args) { - return binding.send('ipc-message', args) + return binding.send('-ipc-message', args) } ipcRenderer.sendSync = function (...args) { - return binding.sendSync('ipc-message-sync', args)[0] + return binding.sendSync('-ipc-message-sync', args)[0] } ipcRenderer.sendToHost = function (...args) { diff --git a/spec/api-web-contents-spec.js b/spec/api-web-contents-spec.js index 4344a7f6a0f44..097b49d2d1f9e 100644 --- a/spec/api-web-contents-spec.js +++ b/spec/api-web-contents-spec.js @@ -995,6 +995,34 @@ describe('webContents module', () => { }) }) + describe('ipc-message event', () => { + it('emits when the renderer process sends an asynchronous message', async () => { + const webContents = remote.getCurrentWebContents() + const promise = emittedOnce(webContents, 'ipc-message') + + ipcRenderer.send('message', 'Hello World!') + + const [, channel, message] = await promise + expect(channel).to.equal('message') + expect(message).to.equal('Hello World!') + }) + }) + + describe('ipc-message-sync event', () => { + it('emits when the renderer process sends a synchronous message', async () => { + const webContents = remote.getCurrentWebContents() + const promise = emittedOnce(webContents, 'ipc-message-sync') + + ipcRenderer.send('handle-next-ipc-message-sync', 'foobar') + const result = ipcRenderer.sendSync('message', 'Hello World!') + + const [, channel, message] = await promise + expect(channel).to.equal('message') + expect(message).to.equal('Hello World!') + expect(result).to.equal('foobar') + }) + }) + describe('referrer', () => { it('propagates referrer information to new target=_blank windows', (done) => { const server = http.createServer((req, res) => { diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 9ef8a7a05c0ff..789dc9fb2de86 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -175,8 +175,8 @@ describe('chromium feature', () => { session: ses } }) - w.webContents.on('ipc-message', (event, args) => { - if (args[0] === 'deviceIds') deviceIds.push(args[1]) + w.webContents.on('ipc-message', (event, channel, deviceId) => { + if (channel === 'deviceIds') deviceIds.push(deviceId) if (deviceIds.length === 2) { assert.notDeepStrictEqual(deviceIds[0], deviceIds[1]) closeWindow(w).then(() => { @@ -216,13 +216,13 @@ describe('chromium feature', () => { partition: 'sw-file-scheme-spec' } }) - w.webContents.on('ipc-message', (event, args) => { - if (args[0] === 'reload') { + w.webContents.on('ipc-message', (event, channel, message) => { + if (channel === 'reload') { w.webContents.reload() - } else if (args[0] === 'error') { - done(args[1]) - } else if (args[0] === 'response') { - assert.strictEqual(args[1], 'Hello from serviceWorker!') + } else if (channel === 'error') { + done(message) + } else if (channel === 'response') { + assert.strictEqual(message, 'Hello from serviceWorker!') session.fromPartition('sw-file-scheme-spec').clearStorageData({ storages: ['serviceworkers'] }, () => done()) @@ -255,13 +255,13 @@ describe('chromium feature', () => { session: customSession } }) - w.webContents.on('ipc-message', (event, args) => { - if (args[0] === 'reload') { + w.webContents.on('ipc-message', (event, channel, message) => { + if (channel === 'reload') { w.webContents.reload() - } else if (args[0] === 'error') { - done(`unexpected error : ${args[1]}`) - } else if (args[0] === 'response') { - assert.strictEqual(args[1], 'Hello from serviceWorker!') + } else if (channel === 'error') { + done(`unexpected error : ${message}`) + } else if (channel === 'response') { + assert.strictEqual(message, 'Hello from serviceWorker!') customSession.clearStorageData({ storages: ['serviceworkers'] }, () => { @@ -298,8 +298,8 @@ describe('chromium feature', () => { partition: 'geolocation-spec' } }) - w.webContents.on('ipc-message', (event, args) => { - if (args[0] === 'success') { + w.webContents.on('ipc-message', (event, channel) => { + if (channel === 'success') { done() } else { done('unexpected response from geolocation api') @@ -584,18 +584,18 @@ describe('chromium feature', () => { describe('window.opener', () => { const url = `file://${fixtures}/pages/window-opener.html` - it('is null for main window', (done) => { + it('is null for main window', async () => { w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } }) - w.webContents.once('ipc-message', (event, args) => { - assert.deepStrictEqual(args, ['opener', null]) - done() - }) + const promise = emittedOnce(w.webContents, 'ipc-message') w.loadFile(path.join(fixtures, 'pages', 'window-opener.html')) + const [, channel, opener] = await promise + expect(channel).to.equal('opener') + expect(opener).to.equal(null) }) it('is not null for window opened by window.open', (done) => { diff --git a/spec/static/main.js b/spec/static/main.js index fd777611a0203..7a49d9190212f 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -235,6 +235,12 @@ app.on('ready', function () { }) }) +ipcMain.on('handle-next-ipc-message-sync', function (event, returnValue) { + event.sender.once('ipc-message-sync', (event, channel, args) => { + event.returnValue = returnValue + }) +}) + for (const eventName of [ 'remote-require', 'remote-get-global', diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 12e179143fa2d..a308ef3695707 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -651,7 +651,7 @@ describe(' tag', function () { }) describe('ipc-message event', () => { - it('emits when guest sends a ipc message to browser', async () => { + it('emits when guest sends an ipc message to browser', async () => { loadWebView(webview, { nodeintegration: 'on', src: `file://${fixtures}/pages/ipc-message.html`