Browse Source

Merge pull request #8142 from electron/1-3-backports

Backports to 1.3
Kevin Sawicki 8 years ago
parent
commit
35be33a02f

+ 1 - 1
lib/browser/api/app.js

@@ -71,7 +71,7 @@ app.allowNTLMCredentialsForAllDomains = function (allow) {
 const events = ['login', 'certificate-error', 'select-client-certificate']
 for (let name of events) {
   app.on(name, (event, webContents, ...args) => {
-    webContents.emit.apply(webContents, [name, event].concat(args))
+    webContents.emit(name, event, ...args)
   })
 }
 

+ 6 - 6
lib/browser/api/browser-window.js

@@ -119,19 +119,19 @@ BrowserWindow.fromDevToolsWebContents = (webContents) => {
 // Helpers.
 Object.assign(BrowserWindow.prototype, {
   loadURL (...args) {
-    return this.webContents.loadURL.apply(this.webContents, args)
+    return this.webContents.loadURL(...args)
   },
   getURL (...args) {
     return this.webContents.getURL()
   },
   reload (...args) {
-    return this.webContents.reload.apply(this.webContents, args)
+    return this.webContents.reload(...args)
   },
   send (...args) {
-    return this.webContents.send.apply(this.webContents, args)
+    return this.webContents.send(...args)
   },
   openDevTools (...args) {
-    return this.webContents.openDevTools.apply(this.webContents, args)
+    return this.webContents.openDevTools(...args)
   },
   closeDevTools () {
     return this.webContents.closeDevTools()
@@ -146,7 +146,7 @@ Object.assign(BrowserWindow.prototype, {
     return this.webContents.toggleDevTools()
   },
   inspectElement (...args) {
-    return this.webContents.inspectElement.apply(this.webContents, args)
+    return this.webContents.inspectElement(...args)
   },
   inspectServiceWorker () {
     return this.webContents.inspectServiceWorker()
@@ -155,7 +155,7 @@ Object.assign(BrowserWindow.prototype, {
     return this.webContents.showDefinitionForSelection()
   },
   capturePage (...args) {
-    return this.webContents.capturePage.apply(this.webContents, args)
+    return this.webContents.capturePage(...args)
   }
 })
 

+ 4 - 4
lib/browser/api/dialog.js

@@ -50,7 +50,7 @@ module.exports = {
   showOpenDialog: function (...args) {
     var prop, properties, value, wrappedCallback
     checkAppInitialized()
-    let [window, options, callback] = parseArgs.apply(null, args)
+    let [window, options, callback] = parseArgs(...args)
     if (options == null) {
       options = {
         title: 'Open',
@@ -97,7 +97,7 @@ module.exports = {
   showSaveDialog: function (...args) {
     var wrappedCallback
     checkAppInitialized()
-    let [window, options, callback] = parseArgs.apply(null, args)
+    let [window, options, callback] = parseArgs(...args)
     if (options == null) {
       options = {
         title: 'Save'
@@ -130,7 +130,7 @@ module.exports = {
   showMessageBox: function (...args) {
     var flags, i, j, len, messageBoxType, ref2, ref3, text
     checkAppInitialized()
-    let [window, options, callback] = parseArgs.apply(null, args)
+    let [window, options, callback] = parseArgs(...args)
     if (options == null) {
       options = {
         type: 'none'
@@ -185,7 +185,7 @@ module.exports = {
   },
 
   showErrorBox: function (...args) {
-    return binding.showErrorBox.apply(binding, args)
+    return binding.showErrorBox(...args)
   }
 }
 

+ 2 - 4
lib/browser/api/navigation-controller.js

@@ -4,13 +4,11 @@ const {ipcMain} = require('electron')
 
 // The history operation in renderer is redirected to browser.
 ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) {
-  var ref
-  (ref = event.sender)[method].apply(ref, args)
+  event.sender[method](...args)
 })
 
 ipcMain.on('ELECTRON_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) {
-  var ref
-  event.returnValue = (ref = event.sender)[method].apply(ref, args)
+  event.returnValue = event.sender[method](...args)
 })
 
 // JavaScript implementation of Chromium's NavigationController.

+ 1 - 1
lib/browser/api/web-contents.js

@@ -237,7 +237,7 @@ WebContents.prototype._init = function () {
   // Delays the page-title-updated event to next tick.
   this.on('-page-title-updated', function (...args) {
     setImmediate(() => {
-      this.emit.apply(this, ['page-title-updated'].concat(args))
+      this.emit('page-title-updated', ...args)
     })
   })
 

+ 3 - 3
lib/browser/guest-window-manager.js

@@ -153,7 +153,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guest
 
   const guestWindow = getGuestWindow(guestContents)
   if (guestWindow != null) {
-    event.returnValue = guestWindow[method].apply(guestWindow, args)
+    event.returnValue = guestWindow[method](...args)
   } else {
     event.returnValue = null
   }
@@ -177,7 +177,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event,
   if (guestContents == null) return
 
   if (canAccessWindow(event.sender, guestContents)) {
-    guestContents[method].apply(guestContents, args)
+    guestContents[method](...args)
   } else {
     console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
   }
@@ -191,7 +191,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (e
   }
 
   if (canAccessWindow(event.sender, guestContents)) {
-    event.returnValue = guestContents[method].apply(guestContents, args)
+    event.returnValue = guestContents[method](...args)
   } else {
     console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
     event.returnValue = null

+ 1 - 1
lib/browser/init.js

@@ -26,7 +26,7 @@ if (process.platform === 'win32') {
   // Redirect node's console to use our own implementations, since node can not
   // handle console output when running as GUI program.
   var consoleLog = function (...args) {
-    return process.log(util.format.apply(util, args) + '\n')
+    return process.log(util.format(...args) + '\n')
   }
   var streamWrite = function (chunk, encoding, callback) {
     if (Buffer.isBuffer(chunk)) {

+ 15 - 7
lib/browser/objects-registry.js

@@ -19,17 +19,14 @@ class ObjectsRegistry {
   // registered then the already assigned ID would be returned.
   add (webContents, obj) {
     // Get or assign an ID to the object.
-    let id = this.saveToStorage(obj)
+    const id = this.saveToStorage(obj)
 
     // Add object to the set of referenced objects.
-    let webContentsId = webContents.getId()
+    const webContentsId = webContents.getId()
     let owner = this.owners[webContentsId]
     if (!owner) {
       owner = this.owners[webContentsId] = new Set()
-      // Clear the storage when webContents is reloaded/navigated.
-      webContents.once('render-view-deleted', () => {
-        this.clear(webContentsId)
-      })
+      this.registerDeleteListener(webContents, webContentsId)
     }
     if (!owner.has(id)) {
       owner.add(id)
@@ -89,8 +86,19 @@ class ObjectsRegistry {
     pointer.count -= 1
     if (pointer.count === 0) {
       v8Util.deleteHiddenValue(pointer.object, 'atomId')
-      return delete this.storage[id]
+      delete this.storage[id]
+    }
+  }
+
+  // Private: Clear the storage when webContents is reloaded/navigated.
+  registerDeleteListener (webContents, webContentsId) {
+    const listener = (event, deletedProcessId) => {
+      if (deletedProcessId === webContentsId) {
+        webContents.removeListener('render-view-deleted', listener)
+        this.clear(webContentsId)
+      }
     }
+    webContents.on('render-view-deleted', listener)
   }
 }
 

+ 31 - 0
lib/browser/rpc-server.js

@@ -371,3 +371,34 @@ ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId
     contents.send(channel, ...args)
   }
 })
+
+// Implements window.alert(message, title)
+ipcMain.on('ELECTRON_BROWSER_WINDOW_ALERT', function (event, message, title) {
+  if (message == null) message = ''
+  if (title == null) title = ''
+
+  event.returnValue = electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
+    message: `${message}`,
+    title: `${title}`,
+    buttons: ['OK']
+  })
+})
+
+// Implements window.confirm(message, title)
+ipcMain.on('ELECTRON_BROWSER_WINDOW_CONFIRM', function (event, message, title) {
+  if (message == null) message = ''
+  if (title == null) title = ''
+
+  event.returnValue = !electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
+    message: `${message}`,
+    title: `${title}`,
+    buttons: ['OK', 'Cancel'],
+    cancelId: 1
+  })
+})
+
+// Implements window.close()
+ipcMain.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) {
+  event.sender.getOwnerBrowserWindow().close()
+  event.returnValue = null
+})

+ 1 - 7
lib/common/api/callbacks-registry.js

@@ -44,14 +44,8 @@ class CallbacksRegistry {
     return (ref = this.callbacks[id]) != null ? ref : function () {}
   }
 
-  call (id, ...args) {
-    var ref
-    return (ref = this.get(id)).call.apply(ref, [global].concat(args))
-  }
-
   apply (id, ...args) {
-    var ref
-    return (ref = this.get(id)).apply.apply(ref, [global].concat(args))
+    return this.get(id).apply(global, ...args)
   }
 
   remove (id) {

+ 4 - 2
lib/common/init.js

@@ -1,11 +1,13 @@
 const timers = require('timers')
 
+const {binding} = process
+
 process.atomBinding = function (name) {
   try {
-    return process.binding('atom_' + process.type + '_' + name)
+    return binding('atom_' + process.type + '_' + name)
   } catch (error) {
     if (/No such module/.test(error.message)) {
-      return process.binding('atom_common_' + name)
+      return binding('atom_common_' + name)
     }
   }
 }

+ 7 - 7
lib/renderer/api/remote.js

@@ -88,7 +88,7 @@ const wrapArgs = function (args, visited) {
       }
     }
   }
-  return Array.prototype.slice.call(args).map(valueToMeta)
+  return args.map(valueToMeta)
 }
 
 // Populate object's members from descriptors.
@@ -100,14 +100,14 @@ const setObjectMembers = function (ref, object, metaId, members) {
 
     let descriptor = { enumerable: member.enumerable }
     if (member.type === 'method') {
-      const remoteMemberFunction = function () {
+      const remoteMemberFunction = function (...args) {
         if (this && this.constructor === remoteMemberFunction) {
           // Constructor call.
-          let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments))
+          let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args))
           return metaToValue(ret)
         } else {
           // Call member function.
-          let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments))
+          let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args))
           return metaToValue(ret)
         }
       }
@@ -213,17 +213,17 @@ const metaToValue = function (meta) {
 
       if (meta.type === 'function') {
         // A shadow class to represent the remote function object.
-        let remoteFunction = function () {
+        let remoteFunction = function (...args) {
           if (this && this.constructor === remoteFunction) {
             // Constructor call.
-            let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments))
+            let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args))
             // Returning object in constructor will replace constructed object
             // with the returned object.
             // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
             return metaToValue(obj)
           } else {
             // Function call.
-            let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments))
+            let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args))
             return metaToValue(obj)
           }
         }

+ 4 - 6
lib/renderer/init.js

@@ -29,20 +29,18 @@ const electron = require('electron')
 
 // Call webFrame method.
 electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
-  electron.webFrame[method].apply(electron.webFrame, args)
+  electron.webFrame[method](...args)
 })
 
 electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_SYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
-  const result = electron.webFrame[method].apply(electron.webFrame, args)
+  const result = electron.webFrame[method](...args)
   event.sender.send(`ELECTRON_INTERNAL_BROWSER_SYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
 })
 
 electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
-  const responseCallback = function (result) {
+  electron.webFrame[method](...args, function (result) {
     event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
-  }
-  args.push(responseCallback)
-  electron.webFrame[method].apply(electron.webFrame, args)
+  })
 })
 
 // Process command line arguments.

+ 24 - 37
lib/renderer/override.js

@@ -1,23 +1,27 @@
 'use strict'
 
-const ipcRenderer = require('electron').ipcRenderer
-const remote = require('electron').remote
+const {ipcRenderer} = require('electron')
+
+const {defineProperty} = Object
 
 // Helper function to resolve relative url.
-var a = window.top.document.createElement('a')
-var resolveURL = function (url) {
+const a = window.top.document.createElement('a')
+const resolveURL = function (url) {
   a.href = url
   return a.href
 }
 
 // Window object returned by "window.open".
-var BrowserWindowProxy = (function () {
+const BrowserWindowProxy = (function () {
   BrowserWindowProxy.proxies = {}
 
   BrowserWindowProxy.getOrCreate = function (guestId) {
-    var base = this.proxies
-    base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId)
-    return base[guestId]
+    let proxy = this.proxies[guestId]
+    if (proxy == null) {
+      proxy = new BrowserWindowProxy(guestId)
+      this.proxies[guestId] = proxy
+    }
+    return proxy
   }
 
   BrowserWindowProxy.remove = function (guestId) {
@@ -25,7 +29,7 @@ var BrowserWindowProxy = (function () {
   }
 
   function BrowserWindowProxy (guestId1) {
-    Object.defineProperty(this, 'guestId', {
+    defineProperty(this, 'guestId', {
       configurable: false,
       enumerable: true,
       writeable: false,
@@ -55,7 +59,7 @@ var BrowserWindowProxy = (function () {
     ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print')
   }
 
-  Object.defineProperty(BrowserWindowProxy.prototype, 'location', {
+  defineProperty(BrowserWindowProxy.prototype, 'location', {
     get: function () {
       return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL')
     },
@@ -73,7 +77,7 @@ var BrowserWindowProxy = (function () {
   }
 
   BrowserWindowProxy.prototype['eval'] = function (...args) {
-    ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args))
+    ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript', ...args)
   }
 
   return BrowserWindowProxy
@@ -82,7 +86,7 @@ var BrowserWindowProxy = (function () {
 if (process.guestInstanceId == null) {
   // Override default window.close.
   window.close = function () {
-    return remote.getCurrentWindow().close()
+    ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
   }
 }
 
@@ -158,29 +162,12 @@ window.open = function (url, frameName, features) {
   }
 }
 
-// Use the dialog API to implement alert().
-window.alert = function (message = '', title = '') {
-  remote.dialog.showMessageBox(remote.getCurrentWindow(), {
-    message: String(message),
-    title: String(title),
-    buttons: ['OK']
-  })
+window.alert = function (message, title) {
+  ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
 }
 
-// And the confirm().
 window.confirm = function (message, title) {
-  var buttons, cancelId
-  if (title == null) {
-    title = ''
-  }
-  buttons = ['OK', 'Cancel']
-  cancelId = 1
-  return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
-    message: message,
-    title: title,
-    buttons: buttons,
-    cancelId: cancelId
-  })
+  return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
 }
 
 // But we do not support prompt().
@@ -205,11 +192,11 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m
 
 // Forward history operations to browser.
 var sendHistoryOperation = function (...args) {
-  ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_NAVIGATION_CONTROLLER'].concat(args))
+  ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
 }
 
 var getHistoryOperation = function (...args) {
-  return ipcRenderer.sendSync.apply(ipcRenderer, ['ELECTRON_SYNC_NAVIGATION_CONTROLLER'].concat(args))
+  return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
 }
 
 window.history.back = function () {
@@ -224,7 +211,7 @@ window.history.go = function (offset) {
   sendHistoryOperation('goToOffset', offset)
 }
 
-Object.defineProperty(window.history, 'length', {
+defineProperty(window.history, 'length', {
   get: function () {
     return getHistoryOperation('length')
   }
@@ -242,13 +229,13 @@ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, vi
 })
 
 // Make document.hidden and document.visibilityState return the correct value.
-Object.defineProperty(document, 'hidden', {
+defineProperty(document, 'hidden', {
   get: function () {
     return cachedVisibilityState !== 'visible'
   }
 })
 
-Object.defineProperty(document, 'visibilityState', {
+defineProperty(document, 'visibilityState', {
   get: function () {
     return cachedVisibilityState
   }

+ 2 - 2
lib/renderer/web-view/guest-view-internal.js

@@ -46,7 +46,7 @@ var DEPRECATED_EVENTS = {
 var dispatchEvent = function (webView, eventName, eventKey, ...args) {
   var domEvent, f, i, j, len, ref1
   if (DEPRECATED_EVENTS[eventName] != null) {
-    dispatchEvent.apply(null, [webView, DEPRECATED_EVENTS[eventName], eventKey].concat(args))
+    dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args)
   }
   domEvent = new Event(eventName)
   ref1 = WEB_VIEW_EVENTS[eventKey]
@@ -63,7 +63,7 @@ var dispatchEvent = function (webView, eventName, eventKey, ...args) {
 module.exports = {
   registerEvents: function (webView, viewInstanceId) {
     ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) {
-      dispatchEvent.apply(null, [webView, eventName, eventName].concat(args))
+      dispatchEvent(webView, eventName, eventName, ...args)
     })
 
     ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) {

+ 2 - 2
lib/renderer/web-view/web-view.js

@@ -407,7 +407,7 @@ var registerWebViewElement = function () {
     return function (...args) {
       const internal = v8Util.getHiddenValue(this, 'internal')
       if (internal.webContents) {
-        return internal.webContents[m].apply(internal.webContents, args)
+        return internal.webContents[m](...args)
       } else {
         throw new Error(`Cannot call ${m} because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.`)
       }
@@ -420,7 +420,7 @@ var registerWebViewElement = function () {
   createNonBlockHandler = function (m) {
     return function (...args) {
       const internal = v8Util.getHiddenValue(this, 'internal')
-      return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m].concat(args))
+      return ipcRenderer.send('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m, ...args)
     }
   }
   for (j = 0, len1 = nonblockMethods.length; j < len1; j++) {

+ 5 - 0
script/cibuild-electron-linux-arm

@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+export TARGET_ARCH=arm
+
+script/cibuild-linux

+ 5 - 0
script/cibuild-electron-linux-ia32

@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+export TARGET_ARCH=ia32
+
+script/cibuild-linux

+ 5 - 0
script/cibuild-electron-linux-x64

@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+export TARGET_ARCH=x64
+
+script/cibuild-linux

+ 23 - 0
script/cibuild-linux

@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+MESSAGE="$(git log --format=%B -n 1 HEAD)"
+case ${MESSAGE} in
+  Bump* ) export ELECTRON_RELEASE=1 ;;
+esac
+
+set +x
+
+export ELECTRON_GITHUB_TOKEN="$BUILD_ELECTRON_ELECTRON_GITHUB_TOKEN"
+export ELECTRON_S3_BUCKET="$BUILD_ELECTRON_ELECTRON_S3_BUCKET"
+export ELECTRON_S3_ACCESS_KEY="$BUILD_ELECTRON_ELECTRON_S3_ACCESS_KEY"
+export ELECTRON_S3_SECRET_KEY="$BUILD_ELECTRON_ELECTRON_S3_SECRET_KEY"
+
+if [[ -z "${ELECTRON_RELEASE}" ]]; then
+  echo "Generating Linux $TARGET_ARCH debug build"
+else
+  echo "Generating Linux $TARGET_ARCH release build"
+fi
+
+set -x
+
+script/cibuild

+ 1 - 1
script/lib/config.py

@@ -9,7 +9,7 @@ import sys
 BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
     'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
 LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \
-    'c5cf295ef93d4ee88bff0c4b06b28ff0969a890e'
+    '27add4cfef98f21d5910539bebb47ae175f024c2'
 
 PLATFORM = {
   'cygwin': 'win32',

+ 15 - 0
spec/api-ipc-spec.js

@@ -492,4 +492,19 @@ describe('ipc module', function () {
       assert.equal(w.listenerCount('test'), 0)
     })
   })
+
+  describe('remote objects registry', function () {
+    it('does not dereference until the render view is deleted (regression)', function (done) {
+      w = new BrowserWindow({
+        show: false
+      })
+
+      ipcMain.once('error-message', (event, message) => {
+        assert(message.startsWith('Cannot read property \'object\' of undefined'), message)
+        done()
+      })
+
+      w.loadURL('file://' + path.join(fixtures, 'api', 'render-view-deleted.html'))
+    })
+  })
 })

+ 32 - 0
spec/fixtures/api/render-view-deleted.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title></title>
+    <script>
+      const {ipcRenderer, remote} = require('electron')
+
+      const contents = remote.getCurrentWebContents()
+
+      // This should not trigger a dereference and a remote getURL call should not fail
+      contents.emit('render-view-deleted', {}, 'not-a-process-id')
+      try {
+        contents.getURL()
+      } catch (error) {
+        ipcRenderer.send('error-message', 'Unexpected error on getURL call')
+      }
+
+      // This should trigger a dereference and a remote getURL call should fail
+      contents.emit('render-view-deleted', {}, contents.getId())
+      try {
+        contents.getURL()
+        ipcRenderer.send('error-message', 'No error thrown')
+      } catch (error) {
+        ipcRenderer.send('error-message', error.message)
+      }
+    </script>
+  </head>
+  <body>
+
+  </body>
+</html>