Browse Source

Merge pull request #11158 from electron/execute-errors

fix: Pass on errors thrown in `executeJavaScript`
Charles Kerr 7 years ago
parent
commit
5eb00e45aa
4 changed files with 53 additions and 1 deletions
  1. 18 1
      lib/browser/api/web-contents.js
  2. 11 0
      lib/renderer/init.js
  3. 20 0
      spec/api-browser-window-spec.js
  4. 4 0
      spec/static/main.js

+ 18 - 1
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)
+        }
       }
     })
   })

+ 11 - 0
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)
       })
   }

+ 20 - 0
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

+ 4 - 0
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) {