From 344458b7d4fea60843257b7dc078cb3bc98b4a79 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:41:41 +0000 Subject: [PATCH 1/7] fix(deps): update dependency axios to v1 --- package.json | 2 +- pnpm-lock.yaml | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 014e9f1a8..0fac5c3fc 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ }, "dependencies": { "@primer/octicons-react": "19.8.0", - "axios": "0.27.2", + "axios": "1.5.1", "date-fns": "2.30.0", "electron-updater": "6.1.4", "final-form": "4.20.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e3362eda..bcbe86733 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ dependencies: specifier: 19.8.0 version: 19.8.0(react@18.2.0) axios: - specifier: 0.27.2 - version: 0.27.2 + specifier: 1.5.1 + version: 1.5.1 date-fns: specifier: 2.30.0 version: 2.30.0 @@ -1541,11 +1541,12 @@ packages: resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} dev: true - /axios@0.27.2: - resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + /axios@1.5.1: + resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} dependencies: follow-redirects: 1.15.2 form-data: 4.0.0 + proxy-from-env: 1.1.0 transitivePeerDependencies: - debug dev: false @@ -4649,6 +4650,10 @@ packages: requiresBuild: true optional: true + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true From c381461940e7514cd1630093ef4c467afbe4ff68 Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Mon, 2 Oct 2023 10:45:26 +0200 Subject: [PATCH 2/7] Use new adapter setting See https://github.com/axios/axios/pull/5277 --- src/hooks/useNotifications.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useNotifications.test.ts b/src/hooks/useNotifications.test.ts index b9ab59296..593689b4a 100644 --- a/src/hooks/useNotifications.test.ts +++ b/src/hooks/useNotifications.test.ts @@ -9,7 +9,7 @@ import { mockedUser } from '../__mocks__/mockedData'; describe('hooks/useNotifications.ts', () => { beforeEach(() => { - axios.defaults.adapter = require('axios/lib/adapters/http'); + axios.defaults.adapter = 'http'; }); describe('fetchNotifications', () => { From 3cf31f5f5f5a76c13fd15f2146f1cb6f846a00cc Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 3 Oct 2023 12:12:32 +0200 Subject: [PATCH 3/7] Fix tests --- jest.config.js | 20 ++++++++++++++++++++ package.json | 12 ------------ src/hooks/useNotifications.test.ts | 2 ++ 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 jest.config.js diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..da0781231 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,20 @@ +const config = { + "preset": "ts-jest/presets/js-with-ts", + "setupFiles": [ + "/src/__helpers__/setupEnvVars.js" + ], + "testEnvironment": "jsdom", + "coverageThreshold": { + "global": { + "lines": 90 + } + }, + "transformIgnorePatterns": ["node_modules\/(?!axios)"], + "moduleNameMapper": { + // Force CommonJS build for http adapter to be available. + // via https://github.com/axios/axios/issues/5101#issuecomment-1276572468 + '^axios$': require.resolve('axios'), + }, +} + +module.exports = config; diff --git a/package.json b/package.json index 0fac5c3fc..9e85b0cd0 100644 --- a/package.json +++ b/package.json @@ -48,18 +48,6 @@ "url": "https://github.com/manosim/gitify/issues" }, "homepage": "https://www.gitify.io/", - "jest": { - "preset": "ts-jest/presets/js-with-ts", - "setupFiles": [ - "/src/__helpers__/setupEnvVars.js" - ], - "testEnvironment": "jsdom", - "coverageThreshold": { - "global": { - "lines": 90 - } - } - }, "build": { "appId": "com.electron.gitify", "productName": "Gitify", diff --git a/src/hooks/useNotifications.test.ts b/src/hooks/useNotifications.test.ts index 593689b4a..dce5e9e18 100644 --- a/src/hooks/useNotifications.test.ts +++ b/src/hooks/useNotifications.test.ts @@ -9,6 +9,8 @@ import { mockedUser } from '../__mocks__/mockedData'; describe('hooks/useNotifications.ts', () => { beforeEach(() => { + // axios will default to using the XHR adapter which can't be intercepted + // by nock. So, configure axios to use the node adapter. axios.defaults.adapter = 'http'; }); From 968ef26f5812c0c4d38fe447c1aff210fa5c3132 Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 3 Oct 2023 12:14:47 +0200 Subject: [PATCH 4/7] Remove unnecessary transform --- jest.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index da0781231..f412fe027 100644 --- a/jest.config.js +++ b/jest.config.js @@ -9,7 +9,6 @@ const config = { "lines": 90 } }, - "transformIgnorePatterns": ["node_modules\/(?!axios)"], "moduleNameMapper": { // Force CommonJS build for http adapter to be available. // via https://github.com/axios/axios/issues/5101#issuecomment-1276572468 From 46d82b4636294719317139c2b3aa277d5e06f958 Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 3 Oct 2023 13:34:48 +0200 Subject: [PATCH 5/7] chore(electron): Move off deprecated remote module --- main.js | 2 ++ package.json | 1 + pnpm-lock.yaml | 11 +++++++++ src/__mocks__/@electron/remote.js | 39 +++++++++++++++++++++++++++++++ src/__mocks__/electron.js | 39 ------------------------------- src/routes/Settings.tsx | 3 ++- src/utils/auth.test.ts | 2 +- src/utils/auth.ts | 3 +-- src/utils/comms.test.ts | 4 +++- src/utils/comms.ts | 3 ++- src/utils/notifications.ts | 2 +- 11 files changed, 63 insertions(+), 46 deletions(-) create mode 100644 src/__mocks__/@electron/remote.js diff --git a/main.js b/main.js index 9f03f89a1..7e9ef229c 100644 --- a/main.js +++ b/main.js @@ -4,6 +4,8 @@ const { autoUpdater } = require('electron-updater'); const { onFirstRunMaybe } = require('./first-run'); const path = require('path'); +require('@electron/remote/main').initialize() + app.setAppUserModelId('com.electron.gitify'); const iconIdle = path.join( diff --git a/package.json b/package.json index 9e85b0cd0..a1dce386b 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "afterSign": "scripts/notarize.js" }, "dependencies": { + "@electron/remote": "^2.0.11", "@primer/octicons-react": "19.8.0", "axios": "1.5.1", "date-fns": "2.30.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcbe86733..3b83d9549 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@electron/remote': + specifier: ^2.0.11 + version: 2.0.11(electron@13.1.7) '@primer/octicons-react': specifier: 19.8.0 version: 19.8.0(react@18.2.0) @@ -566,6 +569,14 @@ packages: - supports-color dev: true + /@electron/remote@2.0.11(electron@13.1.7): + resolution: {integrity: sha512-PYEs7W3GrQNuhgiMHjFEvL5MbAL6C7m1AwSAHGqC+xc33IdP7rcGtJSdTP2eg1ssyB3oI00KwTsiSlsQbAoXpA==} + peerDependencies: + electron: '>= 13.0.0' + dependencies: + electron: 13.1.7 + dev: false + /@electron/universal@1.4.1: resolution: {integrity: sha512-lE/U3UNw1YHuowNbTmKNs9UlS3En3cPgwM5MI+agIgr/B1hSze9NdOP0qn7boZaI9Lph8IDv3/24g9IxnJP7aQ==} engines: {node: '>=8.6'} diff --git a/src/__mocks__/@electron/remote.js b/src/__mocks__/@electron/remote.js new file mode 100644 index 000000000..c775cd2b8 --- /dev/null +++ b/src/__mocks__/@electron/remote.js @@ -0,0 +1,39 @@ +let instance; + +class BrowserWindow { + constructor() { + if (!instance) { + instance = this; + } + return instance; + } + loadURL = jest.fn(); + webContents = { + on: () => {}, + session: { + clearStorageData: jest.fn(), + }, + }; + on() {} + close = jest.fn(); + hide = jest.fn(); + destroy = jest.fn(); +} + +const dialog = { + showErrorBox: jest.fn(), +}; + +module.exports = { + BrowserWindow: BrowserWindow, + dialog: dialog, + process: { + platform: 'darwin', + }, + app: { + getVersion: () => '0.0.1', + getLoginItemSettings: jest.fn(), + setLoginItemSettings: () => {}, + }, + getCurrentWindow: jest.fn(() => instance || new BrowserWindow()), +}; diff --git a/src/__mocks__/electron.js b/src/__mocks__/electron.js index 83fd9ad4c..82251d541 100644 --- a/src/__mocks__/electron.js +++ b/src/__mocks__/electron.js @@ -27,46 +27,7 @@ window.localStorage = { window.alert = jest.fn(); -let instance; - -class BrowserWindow { - constructor() { - if (!instance) { - instance = this; - } - return instance; - } - loadURL = jest.fn(); - webContents = { - on: () => {}, - session: { - clearStorageData: jest.fn(), - }, - }; - on() {} - close = jest.fn(); - hide = jest.fn(); - destroy = jest.fn(); -} - -const dialog = { - showErrorBox: jest.fn(), -}; - module.exports = { - remote: { - BrowserWindow: BrowserWindow, - dialog: dialog, - process: { - platform: 'darwin', - }, - app: { - getVersion: () => '0.0.1', - getLoginItemSettings: jest.fn(), - setLoginItemSettings: () => {}, - }, - getCurrentWindow: jest.fn(() => instance || new BrowserWindow()), - }, ipcRenderer: { send: jest.fn(), on: jest.fn(), diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index a7b929fb6..1e3c118ce 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -1,5 +1,6 @@ import React, { useCallback, useContext } from 'react'; -import { ipcRenderer, remote } from 'electron'; +import { ipcRenderer } from 'electron'; +import remote from '@electron/remote'; import { useNavigate } from 'react-router-dom'; import { ArrowLeftIcon } from '@primer/octicons-react'; diff --git a/src/utils/auth.test.ts b/src/utils/auth.test.ts index 4072e17c7..95d558881 100644 --- a/src/utils/auth.test.ts +++ b/src/utils/auth.test.ts @@ -1,6 +1,6 @@ import { AxiosPromise, AxiosResponse } from 'axios'; -import { remote } from 'electron'; +import remote from '@electron/remote'; const browserWindow = new remote.BrowserWindow(); import * as auth from './auth'; diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 991b19f55..a5d3d405d 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,7 +1,6 @@ import { generateGitHubAPIUrl } from './helpers'; -const { remote } = require('electron'); -const BrowserWindow = remote.BrowserWindow; +const { BrowserWindow } = require('@electron/remote'); import { apiRequest, apiRequestAuth } from '../utils/api-requests'; import { AuthResponse, AuthState, AuthTokenResponse } from '../types'; diff --git a/src/utils/comms.test.ts b/src/utils/comms.test.ts index ce6ff012b..95ea32756 100644 --- a/src/utils/comms.test.ts +++ b/src/utils/comms.test.ts @@ -6,7 +6,9 @@ import { restoreSetting, } from './comms'; -const { ipcRenderer, remote, shell } = require('electron'); +const { ipcRenderer, shell } = require('electron'); + +const remote = require('@electron/remote'); describe('utils/comms.ts', () => { beforeEach(function () { diff --git a/src/utils/comms.ts b/src/utils/comms.ts index 6b2b5a33c..69c03e48b 100644 --- a/src/utils/comms.ts +++ b/src/utils/comms.ts @@ -1,4 +1,5 @@ -const { ipcRenderer, remote, shell } = require('electron'); +const { ipcRenderer, shell } = require('electron'); +const remote = require('@electron/remote'); export function openExternalLink(url: string): void { shell.openExternal(url); diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts index 09350c873..6af31d95e 100644 --- a/src/utils/notifications.ts +++ b/src/utils/notifications.ts @@ -1,4 +1,4 @@ -const { remote } = require('electron'); +const remote = require('@electron/remote'); import { openInBrowser } from '../utils/helpers'; import { reOpenWindow, updateTrayIcon } from './comms'; From 81a8748b892d61dde7fc8d98ca2e041064e05705 Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 3 Oct 2023 13:57:02 +0200 Subject: [PATCH 6/7] Fix platform fetching issue --- main.js | 3 +++ src/__mocks__/electron.js | 1 + src/routes/Settings.tsx | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/main.js b/main.js index 7e9ef229c..7978b2a6c 100644 --- a/main.js +++ b/main.js @@ -77,6 +77,9 @@ menubarApp.on('ready', () => { } } }); + ipcMain.on('get-platform', (event) => { + event.returnValue = process.platform; + }); menubarApp.window.webContents.on('devtools-opened', () => { menubarApp.window.setSize(800, 600); diff --git a/src/__mocks__/electron.js b/src/__mocks__/electron.js index 82251d541..a5e69b633 100644 --- a/src/__mocks__/electron.js +++ b/src/__mocks__/electron.js @@ -31,6 +31,7 @@ module.exports = { ipcRenderer: { send: jest.fn(), on: jest.fn(), + sendSync: () => 'darwin', }, shell: { openExternal: jest.fn(), diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index 1e3c118ce..25d278885 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -14,7 +14,8 @@ import { IconQuit } from '../icons/Quit'; import { updateTrayIcon } from '../utils/comms'; import { setAppearance } from '../utils/appearance'; -const isLinux = remote.process.platform === 'linux'; +const platform = ipcRenderer.sendSync('get-platform'); +const isLinux = platform === 'linux'; export const SettingsRoute: React.FC = () => { const { settings, updateSetting, logout } = useContext(AppContext); From d756682ad450d4ceab26eb16ea62b8b51651d95b Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 3 Oct 2023 17:18:50 +0200 Subject: [PATCH 7/7] Switch to recommended inter-process communication --- main.js | 8 +- src/__mocks__/@electron/remote.js | 1 - src/__mocks__/electron.js | 12 +- src/routes/Settings.test.tsx | 241 ++++++++++++++++++------------ src/routes/Settings.tsx | 23 ++- 5 files changed, 181 insertions(+), 104 deletions(-) diff --git a/main.js b/main.js index 7978b2a6c..8de0d1902 100644 --- a/main.js +++ b/main.js @@ -77,8 +77,12 @@ menubarApp.on('ready', () => { } } }); - ipcMain.on('get-platform', (event) => { - event.returnValue = process.platform; + ipcMain.handle('get-platform', async () => { + return process.platform; + }); + + ipcMain.handle('get-app-version', async () => { + return app.getVersion(); }); menubarApp.window.webContents.on('devtools-opened', () => { diff --git a/src/__mocks__/@electron/remote.js b/src/__mocks__/@electron/remote.js index c775cd2b8..5f7c61648 100644 --- a/src/__mocks__/@electron/remote.js +++ b/src/__mocks__/@electron/remote.js @@ -31,7 +31,6 @@ module.exports = { platform: 'darwin', }, app: { - getVersion: () => '0.0.1', getLoginItemSettings: jest.fn(), setLoginItemSettings: () => {}, }, diff --git a/src/__mocks__/electron.js b/src/__mocks__/electron.js index a5e69b633..25a226c17 100644 --- a/src/__mocks__/electron.js +++ b/src/__mocks__/electron.js @@ -31,7 +31,17 @@ module.exports = { ipcRenderer: { send: jest.fn(), on: jest.fn(), - sendSync: () => 'darwin', + sendSync: jest.fn(), + invoke: jest.fn((channel, ...args) => { + switch (channel) { + case 'get-platform': + return Promise.resolve('darwin'); + case 'get-app-version': + return Promise.resolve('0.0.1'); + default: + return Promise.reject(new Error(`Unknown channel: ${channel}`)); + } + }), }, shell: { openExternal: jest.fn(), diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx index 185b7ac29..a5aedeac6 100644 --- a/src/routes/Settings.test.tsx +++ b/src/routes/Settings.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TestRenderer from 'react-test-renderer'; +import TestRenderer, { act } from 'react-test-renderer'; import { render, fireEvent } from '@testing-library/react'; import { Router } from 'react-router'; import { MemoryRouter } from 'react-router-dom'; @@ -26,29 +26,38 @@ describe('routes/Settings.tsx', () => { updateSetting.mockReset(); }); - it('should render itself & its children', () => { - const tree = TestRenderer.create( - - - - - , - ); + it('should render itself & its children', async () => { + let tree: TestRenderer; + + await act(async () => { + tree = TestRenderer.create( + + + + + , + ); + }); expect(tree).toMatchSnapshot(); }); - it('should press the logout', () => { + it('should press the logout', async () => { const logoutMock = jest.fn(); - - const { getByLabelText } = render( - - - - - , - ); + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Logout')); @@ -59,26 +68,37 @@ describe('routes/Settings.tsx', () => { expect(mockNavigate).toHaveBeenNthCalledWith(1, -1); }); - it('should go back by pressing the icon', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should go back by pressing the icon', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Go Back')); expect(mockNavigate).toHaveBeenNthCalledWith(1, -1); }); - it('should toggle the showOnlyParticipating checkbox', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should toggle the showOnlyParticipating checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Show only participating'), { target: { checked: true }, @@ -88,14 +108,19 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('participating', false); }); - it('should toggle the playSound checkbox', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should toggle the playSound checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Play sound'), { target: { checked: true }, @@ -105,14 +130,19 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('playSound', false); }); - it('should toggle the showNotifications checkbox', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should toggle the showNotifications checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Show notifications'), { target: { checked: true }, @@ -122,14 +152,19 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('showNotifications', false); }); - it('should toggle the onClickMarkAsRead checkbox', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should toggle the onClickMarkAsRead checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Mark as read on click'), { target: { checked: true }, @@ -139,14 +174,19 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('markOnClick', false); }); - it('should toggle the openAtStartup checkbox', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should toggle the openAtStartup checkbox', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Open at startup'), { target: { checked: true }, @@ -156,14 +196,19 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('openAtStartup', false); }); - it('should change the appearance radio group', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should change the appearance radio group', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); fireEvent.click(getByLabelText('Light')); @@ -171,28 +216,40 @@ describe('routes/Settings.tsx', () => { expect(updateSetting).toHaveBeenCalledWith('appearance', 'LIGHT'); }); - it('should go to the enterprise login route', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should go to the enterprise login route', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); + fireEvent.click(getByLabelText('Login with GitHub Enterprise')); expect(mockNavigate).toHaveBeenNthCalledWith(1, '/login-enterprise', { replace: true, }); }); - it('should quit the app', () => { - const { getByLabelText } = render( - - - - - , - ); + it('should quit the app', async () => { + let getByLabelText; + + await act(async () => { + const { getByLabelText: getByLabelTextLocal } = render( + + + + + , + ); + getByLabelText = getByLabelTextLocal; + }); + fireEvent.click(getByLabelText('Quit Gitify')); expect(ipcRenderer.send).toHaveBeenCalledWith('app-quit'); }); diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index 25d278885..f04da658d 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -1,6 +1,5 @@ -import React, { useCallback, useContext } from 'react'; +import React, { useCallback, useContext, useState, useEffect } from 'react'; import { ipcRenderer } from 'electron'; -import remote from '@electron/remote'; import { useNavigate } from 'react-router-dom'; import { ArrowLeftIcon } from '@primer/octicons-react'; @@ -14,13 +13,23 @@ import { IconQuit } from '../icons/Quit'; import { updateTrayIcon } from '../utils/comms'; import { setAppearance } from '../utils/appearance'; -const platform = ipcRenderer.sendSync('get-platform'); -const isLinux = platform === 'linux'; - export const SettingsRoute: React.FC = () => { const { settings, updateSetting, logout } = useContext(AppContext); const navigate = useNavigate(); + const [isLinux, setIsLinux] = useState(false); + const [appVersion, setAppVersion] = useState(null); + + useEffect(() => { + ipcRenderer.invoke('get-platform').then((result: string) => { + setIsLinux(result === 'linux'); + }); + + ipcRenderer.invoke('get-app-version').then((result: string) => { + setAppVersion(result); + }); + }, []); + ipcRenderer.on('update-native-theme', (_, updatedAppearance: Appearance) => { if (settings.appearance === Appearance.SYSTEM) { setAppearance(updatedAppearance); @@ -118,9 +127,7 @@ export const SettingsRoute: React.FC = () => {
- - Gitify v{remote.app.getVersion()} - + Gitify v{appVersion}