fix(sonar): resolve floating promises (typescript:S9383) (#3359) · gitify-app/gitify@9c0cc59 · GitHub
Skip to content

Commit 9c0cc59

Browse files
authored
fix(sonar): resolve floating promises (typescript:S9383) (#3359)
fix(sonar): resolve S9383 floating promises
1 parent 77a5fb8 commit 9c0cc59

13 files changed

Lines changed: 170 additions & 29 deletions

File tree

‎src/main/index.ts‎

Lines changed: 1 addition & 1 deletion

‎src/main/menu.test.ts‎

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,24 @@ vi.mock('electron', () => {
3232
} satisfies Pick<typeof Electron.Menu, 'buildFromTemplate'>,
3333
MenuItem: MockMenuItem,
3434
shell: {
35-
openExternal: vi.fn(),
35+
openExternal: vi.fn(async () => undefined),
3636
} satisfies Pick<Electron.Shell, 'openExternal'>,
3737
};
3838
});
3939

4040
vi.mock('electron-updater', () => ({
4141
autoUpdater: {
42-
checkForUpdatesAndNotify: vi.fn(),
42+
checkForUpdatesAndNotify: vi.fn(async () => undefined),
4343
quitAndInstall: vi.fn(),
4444
},
4545
}));
4646

47+
const logErrorMock = vi.fn();
48+
vi.mock('../shared/logger', () => ({
49+
logError: (...args: unknown[]) => logErrorMock(...args),
50+
toError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))),
51+
}));
52+
4753
vi.mock('./utils', () => ({
4854
takeScreenshot: vi.fn(),
4955
openLogsDirectory: vi.fn(),
@@ -92,7 +98,7 @@ describe('main/menu.ts', () => {
9298
menuItemInstances.length = 0; // Clear tracked instances
9399
menubar = {
94100
app: { quit: vi.fn() },
95-
showWindow: vi.fn(),
101+
showWindow: vi.fn(async () => undefined),
96102
hideWindow: vi.fn(),
97103
refreshContextMenu: vi.fn(),
98104
tray: {
@@ -303,6 +309,71 @@ describe('main/menu.ts', () => {
303309
expect(menubar.app.quit).toHaveBeenCalled();
304310
});
305311

312+
it('logs an error when checking for updates fails', async () => {
313+
const cfg = getMenuItemConfigByLabel('Check for updates');
314+
vi.mocked(autoUpdater.checkForUpdatesAndNotify).mockRejectedValueOnce(
315+
new Error('update failed'),
316+
);
317+
318+
cfg?.click?.();
319+
320+
await vi.waitFor(() =>
321+
expect(logErrorMock).toHaveBeenCalledWith(
322+
'menu',
323+
'Failed to check for updates',
324+
expect.any(Error),
325+
),
326+
);
327+
});
328+
329+
it('logs an error when showing the window fails', async () => {
330+
const cfg = getMenuItemConfigByLabel(`Show ${APPLICATION.NAME}`);
331+
vi.mocked(menubar.showWindow).mockRejectedValueOnce(new Error('show failed'));
332+
333+
cfg?.click?.();
334+
335+
await vi.waitFor(() =>
336+
expect(logErrorMock).toHaveBeenCalledWith(
337+
'menu',
338+
'Failed to show window',
339+
expect.any(Error),
340+
),
341+
);
342+
});
343+
344+
it('logs an error when opening the repository fails', async () => {
345+
const template = buildAndGetTemplate();
346+
const devEntry = template.find((item) => item?.label === 'Developer') as TemplateItem;
347+
const item = devEntry.submenu?.find((i) => i.label === 'Visit Repository');
348+
vi.mocked(shell.openExternal).mockRejectedValueOnce(new Error('open failed'));
349+
350+
item?.click?.();
351+
352+
await vi.waitFor(() =>
353+
expect(logErrorMock).toHaveBeenCalledWith(
354+
'menu',
355+
'Failed to open repository in browser',
356+
expect.any(Error),
357+
),
358+
);
359+
});
360+
361+
it('logs an error when opening the website fails', async () => {
362+
const template = buildAndGetTemplate();
363+
const item = template.find((i) => i.label === 'Visit Website');
364+
vi.mocked(shell.openExternal).mockRejectedValueOnce(new Error('open failed'));
365+
366+
item?.click?.();
367+
368+
await vi.waitFor(() =>
369+
expect(logErrorMock).toHaveBeenCalledWith(
370+
'menu',
371+
'Failed to open website in browser',
372+
expect.any(Error),
373+
),
374+
);
375+
});
376+
306377
it('show window menu item calls showWindow', () => {
307378
const cfg = getMenuItemConfigByLabel(`Show ${APPLICATION.NAME}`);
308379
cfg?.click?.();

‎src/main/menu.ts‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Menubar } from 'electron-menubar';
33
import { autoUpdater } from 'electron-updater';
44

55
import { APPLICATION } from '../shared/constants';
6+
import { logError, toError } from '../shared/logger';
67
import { isMacOS } from '../shared/platform';
78

89
import { resetApp } from './lifecycle/reset';
@@ -32,7 +33,9 @@ export default class MenuBuilder {
3233
label: 'Check for updates',
3334
enabled: true,
3435
click: () => {
35-
autoUpdater.checkForUpdatesAndNotify();
36+
autoUpdater.checkForUpdatesAndNotify().catch((err) => {
37+
logError('menu', 'Failed to check for updates', toError(err));
38+
});
3639
},
3740
});
3841

@@ -61,7 +64,9 @@ export default class MenuBuilder {
6164
label: `Show ${APPLICATION.NAME}`,
6265
visible: true,
6366
click: () => {
64-
this.menubar.showWindow();
67+
this.menubar.showWindow().catch((err) => {
68+
logError('menu', 'Failed to show window', toError(err));
69+
});
6570
},
6671
});
6772

@@ -110,7 +115,11 @@ export default class MenuBuilder {
110115
{
111116
label: 'Visit Repository',
112117
click: () => {
113-
shell.openExternal(`${APPLICATION.GITHUB_BASE_URL}/${APPLICATION.REPO_SLUG}`);
118+
shell
119+
.openExternal(`${APPLICATION.GITHUB_BASE_URL}/${APPLICATION.REPO_SLUG}`)
120+
.catch((err) => {
121+
logError('menu', 'Failed to open repository in browser', toError(err));
122+
});
114123
},
115124
},
116125
{
@@ -125,7 +134,9 @@ export default class MenuBuilder {
125134
{
126135
label: 'Visit Website',
127136
click: () => {
128-
shell.openExternal(APPLICATION.WEBSITE);
137+
shell.openExternal(APPLICATION.WEBSITE).catch((err) => {
138+
logError('menu', 'Failed to open website in browser', toError(err));
139+
});
129140
},
130141
},
131142
{

‎src/main/updater.test.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,22 @@ describe('main/updater.ts', () => {
185185

186186
expect(autoUpdater.quitAndInstall).not.toHaveBeenCalled();
187187
});
188+
189+
it('logs an error when the dialog fails to open', async () => {
190+
vi.mocked(dialog.showMessageBox).mockRejectedValueOnce(new Error('dialog failed'));
191+
192+
await updater.start();
193+
194+
emit('update-downloaded', { releaseName: 'v9.9.9' });
195+
196+
await vi.waitFor(() =>
197+
expect(logError).toHaveBeenCalledWith(
198+
'app updater',
199+
'Failed to show update ready dialog',
200+
expect.any(Error),
201+
),
202+
);
203+
});
188204
});
189205

190206
describe('update event handlers & scheduling', () => {

‎src/main/updater.ts‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,15 @@ export default class AppUpdater {
218218
detail: 'Restart to apply the update. You can also restart later from the tray menu.',
219219
};
220220

221-
dialog.showMessageBox(dialogOpts).then((returnValue) => {
222-
if (returnValue.response === 0) {
223-
autoUpdater.quitAndInstall();
224-
}
225-
});
221+
dialog
222+
.showMessageBox(dialogOpts)
223+
.then((returnValue) => {
224+
if (returnValue.response === 0) {
225+
autoUpdater.quitAndInstall();
226+
}
227+
})
228+
.catch((err) => {
229+
logError('app updater', 'Failed to show update ready dialog', toError(err));
230+
});
226231
}
227232
}

‎src/main/utils.test.ts‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const logErrorMock = vi.fn();
4545
vi.mock('../shared/logger', () => ({
4646
logInfo: (...a: unknown[]) => logInfoMock(...a),
4747
logError: (...a: unknown[]) => logErrorMock(...a),
48+
toError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))),
4849
}));
4950

5051
import { shell } from 'electron';
@@ -82,6 +83,22 @@ describe('main/utils', () => {
8283
expect.stringContaining('Screenshot saved'),
8384
);
8485
});
86+
87+
it('logs an error when capturing the window fails', async () => {
88+
const mb = {
89+
window: { capturePage: () => Promise.reject(new Error('capture failed')) },
90+
};
91+
92+
await takeScreenshot(mb as unknown as Menubar);
93+
94+
await vi.waitFor(() =>
95+
expect(logErrorMock).toHaveBeenCalledWith(
96+
'takeScreenshot',
97+
'Failed to capture window',
98+
expect.any(Error),
99+
),
100+
);
101+
});
85102
});
86103

87104
describe('openLogsDirectory', () => {
@@ -99,5 +116,19 @@ describe('main/utils', () => {
99116
expect.any(Error),
100117
);
101118
});
119+
120+
it('logs an error when opening the directory fails', async () => {
121+
vi.mocked(shell.openPath).mockRejectedValueOnce(new Error('open failed'));
122+
123+
openLogsDirectory();
124+
125+
await vi.waitFor(() =>
126+
expect(logErrorMock).toHaveBeenCalledWith(
127+
'openLogsDirectory',
128+
'Failed to open logs directory',
129+
expect.any(Error),
130+
),
131+
);
132+
});
102133
});
103134
});

‎src/main/utils.ts‎

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import log from 'electron-log';
77
import type { Menubar } from 'electron-menubar';
88

99
import { APPLICATION } from '../shared/constants';
10-
import { logError, logInfo } from '../shared/logger';
10+
import { logError, logInfo, toError } from '../shared/logger';
1111

1212
/**
1313
* Returns true when the app is running in development mode (i.e. not packaged).
@@ -34,11 +34,16 @@ export function takeScreenshot(mb: Menubar) {
3434
return;
3535
}
3636

37-
mb.window.capturePage().then((img) => {
38-
fs.writeFile(capturedPicFilePath, img.toPNG(), () =>
39-
logInfo('takeScreenshot', `Screenshot saved ${capturedPicFilePath}`),
40-
);
41-
});
37+
mb.window
38+
.capturePage()
39+
.then((img) => {
40+
fs.writeFile(capturedPicFilePath, img.toPNG(), () =>
41+
logInfo('takeScreenshot', `Screenshot saved ${capturedPicFilePath}`),
42+
);
43+
})
44+
.catch((err) => {
45+
logError('takeScreenshot', 'Failed to capture window', toError(err));
46+
});
4247
}
4348

4449
/**
@@ -58,5 +63,7 @@ export function openLogsDirectory() {
5863
}
5964

6065
const logDirectory = path.dirname(logFilePath);
61-
shell.openPath(logDirectory);
66+
shell.openPath(logDirectory).catch((err) => {
67+
logError('openLogsDirectory', 'Failed to open logs directory', toError(err));
68+
});
6269
}

‎src/renderer/components/notifications/NotificationRow.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ export const NotificationRow: FC<NotificationRowProps> = ({
7272
};
7373

7474
const actionNotificationInteraction = () => {
75-
openNotification(notification);
75+
void openNotification(notification);
7676

77-
runAction(() =>
77+
void runAction(() =>
7878
markAsDoneOnOpen
7979
? markNotificationsAsDone([notification])
8080
: markNotificationsAsRead([notification]),

‎src/renderer/components/primitives/EmojiText.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const EmojiText: FC<IEmojiText> = ({ text }) => {
2525
}
2626
};
2727

28-
updateEmojiText();
28+
void updateEmojiText();
2929

3030
return () => {
3131
mountedRef.current = false;

‎src/renderer/components/primitives/Header.tsx‎

Lines changed: 1 addition & 1 deletion

0 commit comments

Comments
 (0)