diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index a6e9b7ce827..6eb508d1488 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -22,6 +22,8 @@ process.on('exit', () => { ipcRendererInternal.send(command, contextId); }); +const IS_REMOTE_PROXY = Symbol('is-remote-proxy'); + // Convert the arguments object into an array of meta data. function wrapArgs (args, visited = new Set()) { const valueToMeta = (value) => { @@ -188,6 +190,7 @@ function proxyFunctionProperties (remoteMemberFunction, metaId, name) { return true; }, get: (target, property, receiver) => { + if (property === IS_REMOTE_PROXY) return true; if (!Object.prototype.hasOwnProperty.call(target, property)) loadRemoteProperties(); const value = target[property]; if (property === 'toString' && typeof value === 'function') { @@ -247,7 +250,9 @@ function metaToValue (meta) { setObjectMembers(ret, ret, meta.id, meta.members); setObjectPrototype(ret, ret, meta.id, meta.proto); - Object.defineProperty(ret.constructor, 'name', { value: meta.name }); + if (ret.constructor && ret.constructor[IS_REMOTE_PROXY]) { + Object.defineProperty(ret.constructor, 'name', { value: meta.name }); + } // Track delegate obj's lifetime & tell browser to clean up when object is GCed. v8Util.setRemoteObjectFreer(ret, contextId, meta.id); diff --git a/spec-main/api-remote-spec.ts b/spec-main/api-remote-spec.ts index 5938d258d0f..571cc7c5b9a 100644 --- a/spec-main/api-remote-spec.ts +++ b/spec-main/api-remote-spec.ts @@ -283,11 +283,9 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => { remotely.it(path.join(fixtures, 'module', 'no-prototype.js'))('should work when object has no prototype', (module: string) => { const a = require('electron').remote.require(module); - expect(a.foo.constructor.name).to.equal(''); expect(a.foo.bar).to.equal('baz'); expect(a.foo.baz).to.equal(false); expect(a.bar).to.equal(1234); - expect(a.anonymous.constructor.name).to.equal(''); expect(a.getConstructorName(Object.create(null))).to.equal(''); expect(a.getConstructorName(new (class {})())).to.equal(''); }); @@ -436,7 +434,8 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => { }); describe('remote object in renderer', () => { - const remotely = makeRemotely(makeWindow()); + const win = makeWindow(); + const remotely = makeRemotely(win); remotely.it(fixtures)('can change its properties', (fixtures: string) => { const module = require('path').join(fixtures, 'module', 'property.js'); @@ -500,6 +499,15 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => { global.gc(); stringify({}); }); + + it('can handle objects without constructors', async () => { + win().webContents.once('remote-get-global', (event) => { + class Foo { bar () { return 'bar'; } } + Foo.prototype.constructor = undefined as any; + event.returnValue = new Foo(); + }); + expect(await remotely(() => require('electron').remote.getGlobal('test').bar())).to.equal('bar'); + }); }); describe('remote value in browser', () => {