From a86e48f7ff1c2939f5b4a6884e39db96edf234e0 Mon Sep 17 00:00:00 2001 From: Doug Ayers <4142577+douglascayers@users.noreply.github.com> Date: Thu, 1 Feb 2024 05:06:56 -0600 Subject: [PATCH] fix: ElectronExternalApi fallback to super when electron app is undefined, fixes #399 (#400) * fix: ElectronExternalApi fallback to super when electron app is undefined; accept electron arg * test: ElectronExternalApi fallbacks to super when electron app is undefined * chore: Comsetic changes --- src/main/ElectronExternalApi.js | 63 ++++++++++++------- .../__specs__/ElectronExternalApi.spec.js | 59 +++++++++++++++++ src/main/index.js | 3 +- 3 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 src/main/__specs__/ElectronExternalApi.spec.js diff --git a/src/main/ElectronExternalApi.js b/src/main/ElectronExternalApi.js index 45d8840..29c8a7a 100644 --- a/src/main/ElectronExternalApi.js +++ b/src/main/ElectronExternalApi.js @@ -1,16 +1,31 @@ 'use strict'; -const electron = require('electron'); const path = require('path'); const NodeExternalApi = require('../node/NodeExternalApi'); class ElectronExternalApi extends NodeExternalApi { + /** + * @type {typeof Electron} + */ + electron = undefined; + + /** + * @param {object} options + * @param {typeof Electron} [options.electron] + */ + constructor({ electron } = {}) { + super(); + this.electron = electron; + } + getAppName() { + let appName; try { - return electron.app?.name || electron.app?.getName(); + appName = this.electron.app?.name || this.electron.app?.getName(); } catch { - return super.getAppName(); + // fallback to default value below } + return appName || super.getAppName(); } getAppUserDataPath(appName) { @@ -18,11 +33,13 @@ class ElectronExternalApi extends NodeExternalApi { } getAppVersion() { + let appVersion; try { - return electron.app?.getVersion(); + appVersion = this.electron.app?.getVersion(); } catch { - return super.getAppVersion(); + // fallback to default value below } + return appVersion || super.getAppVersion(); } getElectronLogPath() { @@ -36,7 +53,7 @@ class ElectronExternalApi extends NodeExternalApi { */ getPath(name) { try { - return electron.app?.getPath(name); + return this.electron.app?.getPath(name); } catch { return undefined; } @@ -55,8 +72,8 @@ class ElectronExternalApi extends NodeExternalApi { } isDev() { - if (electron.app?.isPackaged !== undefined) { - return !electron.app.isPackaged; + if (this.electron.app?.isPackaged !== undefined) { + return !this.electron.app.isPackaged; } if (typeof process.execPath === 'string') { @@ -68,36 +85,36 @@ class ElectronExternalApi extends NodeExternalApi { } onAppEvent(eventName, handler) { - electron.app?.on(eventName, handler); + this.electron.app?.on(eventName, handler); return () => { - electron.app?.off(eventName, handler); + this.electron.app?.off(eventName, handler); }; } onAppReady(handler) { - if (electron.app?.isReady()) { + if (this.electron.app?.isReady()) { handler(); - } else if (electron.app?.once) { - electron.app?.once('ready', handler); + } else if (this.electron.app?.once) { + this.electron.app?.once('ready', handler); } else { handler(); } } onEveryWebContentsEvent(eventName, handler) { - electron.webContents?.getAllWebContents().forEach((webContents) => { + this.electron.webContents?.getAllWebContents()?.forEach((webContents) => { webContents.on(eventName, handler); }); - electron.app?.on('web-contents-created', onWebContentsCreated); + this.electron.app?.on('web-contents-created', onWebContentsCreated); return () => { - electron.webContents?.getAllWebContents().forEach((webContents) => { + this.electron.webContents?.getAllWebContents().forEach((webContents) => { webContents.off(eventName, handler); }); - electron.app?.off('web-contents-created', onWebContentsCreated); + this.electron.app?.off('web-contents-created', onWebContentsCreated); }; function onWebContentsCreated(_, webContents) { @@ -111,11 +128,11 @@ class ElectronExternalApi extends NodeExternalApi { * @param {function} listener */ onIpc(channel, listener) { - electron.ipcMain?.on(channel, listener); + this.electron.ipcMain?.on(channel, listener); } onIpcInvoke(channel, listener) { - electron.ipcMain?.handle?.(channel, listener); + this.electron.ipcMain?.handle?.(channel, listener); } /** @@ -123,13 +140,13 @@ class ElectronExternalApi extends NodeExternalApi { * @param {Function} [logFunction] */ openUrl(url, logFunction = console.error) { // eslint-disable-line no-console - electron.shell?.openExternal(url).catch(logFunction); + this.electron.shell?.openExternal(url).catch(logFunction); } setPreloadFileForSessions({ filePath, includeFutureSession = true, - getSessions = () => [electron.session?.defaultSession], + getSessions = () => [this.electron.session?.defaultSession], }) { for (const session of getSessions().filter(Boolean)) { setPreload(session); @@ -155,7 +172,7 @@ class ElectronExternalApi extends NodeExternalApi { * @param {any} message */ sendIpc(channel, message) { - electron.BrowserWindow?.getAllWindows().forEach((wnd) => { + this.electron.BrowserWindow?.getAllWindows()?.forEach((wnd) => { if (wnd.webContents?.isDestroyed() === false) { wnd.webContents.send(channel, message); } @@ -163,7 +180,7 @@ class ElectronExternalApi extends NodeExternalApi { } showErrorBox(title, message) { - electron.dialog?.showErrorBox(title, message); + this.electron.dialog?.showErrorBox(title, message); } } diff --git a/src/main/__specs__/ElectronExternalApi.spec.js b/src/main/__specs__/ElectronExternalApi.spec.js new file mode 100644 index 0000000..1817553 --- /dev/null +++ b/src/main/__specs__/ElectronExternalApi.spec.js @@ -0,0 +1,59 @@ +'use strict'; + +const humilePkg = require('humile/package.json'); +const ElectronExternalApi = require('../ElectronExternalApi'); + +describe('ElectronExternalApi', () => { + describe('getAppName', () => { + it('gets the electron app name property', () => { + const electron = { + app: { + name: 'test-prop', + getName: () => 'test-func', + }, + }; + + expect(api({ electron }).getAppName()).toBe('test-prop'); + }); + + it('calls the electron app name function when no name property', () => { + const electron = { + app: { + name: undefined, + getName: () => 'test-func', + }, + }; + + expect(api({ electron }).getAppName()).toBe('test-func'); + }); + + it('fallsback to super function when no electron names', () => { + const electron = { + app: { + name: undefined, + getName: undefined, + }, + }; + + expect(api({ electron }).getAppName()).toBe(humilePkg.name); + }); + + it('fallsback to super function when no electron', () => { + const electron = undefined; + + expect(api({ electron }).getAppName()).toBe(humilePkg.name); + }); + }); + + /** + * @param {object} options + * @param {NodeJS.Platform} options.platform + * @param {typeof Electron} options.electron + * @returns {ElectronExternalApi} + */ + function api({ electron, platform = process.platform } = {}) { + const externalApi = new ElectronExternalApi({ electron }); + externalApi.setPlatform(platform); + return externalApi; + } +}); diff --git a/src/main/index.js b/src/main/index.js index f52e807..251ed4b 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,10 +1,11 @@ 'use strict'; +const electron = require('electron'); const ElectronExternalApi = require('./ElectronExternalApi'); const { initialize } = require('./initialize'); const createDefaultLogger = require('../node/createDefaultLogger'); -const externalApi = new ElectronExternalApi(); +const externalApi = new ElectronExternalApi({ electron }); const defaultLogger = createDefaultLogger({ dependencies: { externalApi }, initializeFn: initialize,