diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 4e3ec332ae..61b37f7733 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -112,6 +112,16 @@ const webFrameMethods = [ ] const webFrameMethodsWithResult = [] +const errorConstructors = { + Error, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError +} + const asyncWebFrameMethods = function (requestId, method, callback, ...args) { return new Promise((resolve, reject) => { this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args) @@ -120,7 +130,14 @@ const asyncWebFrameMethods = function (requestId, method, callback, ...args) { if (typeof callback === 'function') callback(result) resolve(result) } else { - reject(error) + if (error.__ELECTRON_SERIALIZED_ERROR__ && errorConstructors[error.name]) { + const rehydratedError = new errorConstructors[error.name](error.message) + rehydratedError.stack = error.stack + + reject(rehydratedError) + } else { + reject(error) + } } }) }) diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 9c47a7537b..0d1a251c4d 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -45,6 +45,17 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, null, resolvedResult) }) .catch((resolvedError) => { + if (resolvedError instanceof Error) { + // Errors get lost, because: JSON.stringify(new Error('Message')) === {} + // Take the serializable properties and construct a generic object + resolvedError = { + message: resolvedError.message, + stack: resolvedError.stack, + name: resolvedError.name, + __ELECTRON_SERIALIZED_ERROR__: true + } + } + event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, resolvedError) }) } diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 185b8fba82..fea4c3a739 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -2514,6 +2514,15 @@ describe('BrowserWindow module', () => { const code = `(() => "${expected}")()` const asyncCode = `(() => new Promise(r => setTimeout(() => r("${expected}"), 500)))()` const badAsyncCode = `(() => new Promise((r, e) => setTimeout(() => e("${expectedErrorMsg}"), 500)))()` + const errorTypes = new Set([ + Error, + ReferenceError, + EvalError, + RangeError, + SyntaxError, + TypeError, + URIError + ]) it('doesnt throw when no calback is provided', () => { const result = ipcRenderer.sendSync('executeJavaScript', code, false) @@ -2561,6 +2570,17 @@ describe('BrowserWindow module', () => { done() }) }) + it('rejects the returned promise with an error if an Error.prototype is thrown', async () => { + for (const error in errorTypes) { + await new Promise((resolve) => { + ipcRenderer.send('executeJavaScript', `Promise.reject(new ${error.name}("Wamp-wamp")`, true) + ipcRenderer.once('executeJavaScript-promise-error-name', (event, name) => { + assert.equal(name, error.name) + resolve() + }) + }) + } + }) it('works after page load and during subframe load', (done) => { w.webContents.once('did-finish-load', () => { // initiate a sub-frame load, then try and execute script during it diff --git a/spec/static/main.js b/spec/static/main.js index faede549a1..4a4dfd109d 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -217,6 +217,10 @@ app.on('ready', function () { window.webContents.send('executeJavaScript-promise-response', result) }).catch((error) => { window.webContents.send('executeJavaScript-promise-error', error) + + if (error && error.name) { + window.webContents.send('executeJavaScript-promise-error-name', error.name) + } }) if (!hasCallback) {