diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index d61cce62c9051..0c14ad0e8b96b 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1042,6 +1042,17 @@ contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1" }) ``` +#### `contents.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture])` + +* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here. +* `scripts` [WebSource[]](structures/web-source.md) +* `userGesture` Boolean (optional) - Default is `false`. + +Returns `Promise` - A promise that resolves with the result of the executed code +or is rejected if the result of the code is a rejected promise. + +Works like `executeJavaScript` but evaluates `scripts` in an isolated context. + #### `contents.setIgnoreMenuShortcuts(ignore)` _Experimental_ * `ignore` Boolean diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 6b5f82ddb4c96..d8dd7b1d9c1f2 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -183,22 +183,25 @@ for (const method of webFrameMethods) { } } -const executeJavaScript = (contents, code, hasUserGesture) => { - return ipcMainUtils.invokeInWebContents(contents, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture) +const waitTillCanExecuteJavaScript = async (webContents) => { + if (webContents.getURL() && !webContents.isLoadingMainFrame()) return + + return new Promise((resolve) => { + webContents.once('did-stop-loading', () => { + resolve() + }) + }) } // Make sure WebContents::executeJavaScript would run the code only when the // WebContents has been loaded. -WebContents.prototype.executeJavaScript = function (code, hasUserGesture) { - if (this.getURL() && !this.isLoadingMainFrame()) { - return executeJavaScript(this, code, hasUserGesture) - } else { - return new Promise((resolve, reject) => { - this.once('did-stop-loading', () => { - executeJavaScript(this, code, hasUserGesture).then(resolve, reject) - }) - }) - } +WebContents.prototype.executeJavaScript = async function (code, hasUserGesture) { + await waitTillCanExecuteJavaScript(this) + return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture) +} +WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (code, hasUserGesture) { + await waitTillCanExecuteJavaScript(this) + return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScriptInIsolatedWorld', code, hasUserGesture) } // Translate the options of printToPDF. diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 9e871a1563af5..02f9d893532d2 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -219,6 +219,23 @@ describe('webContents module', () => { }) }) + describe('webContents.executeJavaScriptInIsolatedWorld', () => { + let w: BrowserWindow + + before(async () => { + w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }) + await w.loadURL('about:blank') + }) + + it('resolves the returned promise with the result', async () => { + await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X = 123' }]) + const isolatedResult = await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X' }]) + const mainWorldResult = await w.webContents.executeJavaScript('window.X') + expect(isolatedResult).to.equal(123) + expect(mainWorldResult).to.equal(undefined) + }) + }) + describe('loadURL() promise API', () => { let w: BrowserWindow beforeEach(async () => {