Skip to content

Commit e72f33f

Browse files
committed
fix tests
Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent d2cb5a6 commit e72f33f

1 file changed

Lines changed: 161 additions & 78 deletions

File tree

src/renderer/context/App.test.tsx

Lines changed: 161 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
import { act, fireEvent, waitFor } from '@testing-library/react';
1+
import { act, waitFor } from '@testing-library/react';
22

33
import { renderWithAppContext } from '../__helpers__/test-utils';
4+
import { mockGitHubCloudAccount } from '../__mocks__/account-mocks';
45
import { mockGitifyNotification } from '../__mocks__/notifications-mocks';
56
import { mockSettings } from '../__mocks__/state-mocks';
6-
import { mockRawUser } from '../utils/api/__mocks__/response-mocks';
77

88
import { Constants } from '../constants';
99

1010
import { useAppContext } from '../hooks/useAppContext';
1111
import { useNotifications } from '../hooks/useNotifications';
1212

13-
import type { AuthState, SettingsState } from '../types';
14-
13+
import type {
14+
AuthState,
15+
ClientID,
16+
ClientSecret,
17+
Hostname,
18+
SettingsState,
19+
Token,
20+
} from '../types';
21+
import type { DeviceFlowSession } from '../utils/auth/types';
22+
23+
import * as authUtils from '../utils/auth/utils';
1524
import * as notifications from '../utils/notifications/notifications';
1625
import * as storage from '../utils/storage';
1726
import * as tray from '../utils/tray';
@@ -20,45 +29,30 @@ import { defaultSettings } from './defaults';
2029

2130
jest.mock('../hooks/useNotifications');
2231

23-
// Helper to render a button that calls a context method when clicked
24-
const renderContextButton = (
25-
contextMethodName: keyof AppContextState,
26-
...args: unknown[]
27-
) => {
28-
const TestComponent = () => {
29-
const context = useAppContext();
30-
31-
const method = context[contextMethodName];
32-
return (
33-
<button
34-
data-testid="context-method-button"
35-
onClick={() => {
36-
if (typeof method === 'function') {
37-
(method as (...args: unknown[]) => void)(...args);
38-
}
39-
}}
40-
type="button"
41-
>
42-
{String(contextMethodName)}
43-
</button>
44-
);
32+
// Helper to render the context
33+
const renderWithContext = () => {
34+
let context!: AppContextState;
35+
36+
const CaptureContext = () => {
37+
context = useAppContext();
38+
return null;
4539
};
4640

47-
const result = renderWithAppContext(
41+
renderWithAppContext(
4842
<AppProvider>
49-
<TestComponent />
43+
<CaptureContext />
5044
</AppProvider>,
5145
);
5246

53-
const button = result.getByTestId('context-method-button');
54-
return { ...result, button };
47+
return () => context;
5548
};
5649

5750
describe('renderer/context/App.tsx', () => {
58-
const mockFetchNotifications = jest.fn();
51+
const fetchNotificationsMock = jest.fn();
5952
const markNotificationsAsReadMock = jest.fn();
6053
const markNotificationsAsDoneMock = jest.fn();
6154
const unsubscribeNotificationMock = jest.fn();
55+
const removeAccountNotificationsMock = jest.fn();
6256

6357
const saveStateSpy = jest
6458
.spyOn(storage, 'saveState')
@@ -67,10 +61,11 @@ describe('renderer/context/App.tsx', () => {
6761
beforeEach(() => {
6862
jest.useFakeTimers();
6963
(useNotifications as jest.Mock).mockReturnValue({
70-
fetchNotifications: mockFetchNotifications,
64+
fetchNotifications: fetchNotificationsMock,
7165
markNotificationsAsRead: markNotificationsAsReadMock,
7266
markNotificationsAsDone: markNotificationsAsDoneMock,
7367
unsubscribeNotification: unsubscribeNotificationMock,
68+
removeAccountNotifications: removeAccountNotificationsMock,
7469
});
7570
});
7671

@@ -101,47 +96,48 @@ describe('renderer/context/App.tsx', () => {
10196
renderWithAppContext(<AppProvider>{null}</AppProvider>);
10297

10398
await waitFor(() =>
104-
expect(mockFetchNotifications).toHaveBeenCalledTimes(1),
99+
expect(fetchNotificationsMock).toHaveBeenCalledTimes(1),
105100
);
106101

107102
act(() => {
108103
jest.advanceTimersByTime(
109104
Constants.DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS,
110105
);
111106
});
112-
expect(mockFetchNotifications).toHaveBeenCalledTimes(2);
107+
expect(fetchNotificationsMock).toHaveBeenCalledTimes(2);
113108

114109
act(() => {
115110
jest.advanceTimersByTime(
116111
Constants.DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS,
117112
);
118113
});
119-
expect(mockFetchNotifications).toHaveBeenCalledTimes(3);
114+
expect(fetchNotificationsMock).toHaveBeenCalledTimes(3);
120115

121116
act(() => {
122117
jest.advanceTimersByTime(
123118
Constants.DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS,
124119
);
125120
});
126-
expect(mockFetchNotifications).toHaveBeenCalledTimes(4);
121+
expect(fetchNotificationsMock).toHaveBeenCalledTimes(4);
127122
});
128123

129124
it('should call fetchNotifications', async () => {
130-
const { button } = renderContextButton('fetchNotifications');
131-
132-
mockFetchNotifications.mockReset();
125+
const getContext = renderWithContext();
126+
fetchNotificationsMock.mockReset();
133127

134-
fireEvent.click(button);
128+
act(() => {
129+
getContext().fetchNotifications();
130+
});
135131

136-
expect(mockFetchNotifications).toHaveBeenCalledTimes(1);
132+
expect(fetchNotificationsMock).toHaveBeenCalledTimes(1);
137133
});
138134

139135
it('should call markNotificationsAsRead', async () => {
140-
const { button } = renderContextButton('markNotificationsAsRead', [
141-
mockGitifyNotification,
142-
]);
136+
const getContext = renderWithContext();
143137

144-
fireEvent.click(button);
138+
act(() => {
139+
getContext().markNotificationsAsRead([mockGitifyNotification]);
140+
});
145141

146142
expect(markNotificationsAsReadMock).toHaveBeenCalledTimes(1);
147143
expect(markNotificationsAsReadMock).toHaveBeenCalledWith(
@@ -152,11 +148,11 @@ describe('renderer/context/App.tsx', () => {
152148
});
153149

154150
it('should call markNotificationsAsDone', async () => {
155-
const { button } = renderContextButton('markNotificationsAsDone', [
156-
mockGitifyNotification,
157-
]);
151+
const getContext = renderWithContext();
158152

159-
fireEvent.click(button);
153+
act(() => {
154+
getContext().markNotificationsAsDone([mockGitifyNotification]);
155+
});
160156

161157
expect(markNotificationsAsDoneMock).toHaveBeenCalledTimes(1);
162158
expect(markNotificationsAsDoneMock).toHaveBeenCalledWith(
@@ -167,12 +163,11 @@ describe('renderer/context/App.tsx', () => {
167163
});
168164

169165
it('should call unsubscribeNotification', async () => {
170-
const { button } = renderContextButton(
171-
'unsubscribeNotification',
172-
mockGitifyNotification,
173-
);
166+
const getContext = renderWithContext();
174167

175-
fireEvent.click(button);
168+
act(() => {
169+
getContext().unsubscribeNotification(mockGitifyNotification);
170+
});
176171

177172
expect(unsubscribeNotificationMock).toHaveBeenCalledTimes(1);
178173
expect(unsubscribeNotificationMock).toHaveBeenCalledWith(
@@ -189,13 +184,11 @@ describe('renderer/context/App.tsx', () => {
189184
.mockImplementation(jest.fn());
190185

191186
it('should call updateSetting', async () => {
192-
const { button } = renderContextButton(
193-
'updateSetting',
194-
'participating',
195-
true,
196-
);
187+
const getContext = renderWithContext();
197188

198-
fireEvent.click(button);
189+
act(() => {
190+
getContext().updateSetting('participating', true);
191+
});
199192

200193
expect(saveStateSpy).toHaveBeenCalledWith({
201194
auth: {
@@ -209,9 +202,11 @@ describe('renderer/context/App.tsx', () => {
209202
});
210203

211204
it('should call resetSettings', async () => {
212-
const { button } = renderContextButton('resetSettings');
205+
const getContext = renderWithContext();
213206

214-
fireEvent.click(button);
207+
act(() => {
208+
getContext().resetSettings();
209+
});
215210

216211
expect(saveStateSpy).toHaveBeenCalledWith({
217212
auth: {
@@ -224,14 +219,11 @@ describe('renderer/context/App.tsx', () => {
224219

225220
describe('filter methods', () => {
226221
it('should call updateFilter - checked', async () => {
227-
const { button } = renderContextButton(
228-
'updateFilter',
229-
'filterReasons',
230-
'assign',
231-
true,
232-
);
222+
const getContext = renderWithContext();
233223

234-
fireEvent.click(button);
224+
act(() => {
225+
getContext().updateFilter('filterReasons', 'assign', true);
226+
});
235227

236228
expect(saveStateSpy).toHaveBeenCalledWith({
237229
auth: {
@@ -245,14 +237,11 @@ describe('renderer/context/App.tsx', () => {
245237
});
246238

247239
it('should call updateFilter - unchecked', async () => {
248-
const { button } = renderContextButton(
249-
'updateFilter',
250-
'filterReasons',
251-
'assign',
252-
false,
253-
);
240+
const getContext = renderWithContext();
254241

255-
fireEvent.click(button);
242+
act(() => {
243+
getContext().updateFilter('filterReasons', 'assign', false);
244+
});
256245

257246
expect(saveStateSpy).toHaveBeenCalledWith({
258247
auth: {
@@ -266,9 +255,11 @@ describe('renderer/context/App.tsx', () => {
266255
});
267256

268257
it('should clear filters back to default', async () => {
269-
const { button } = renderContextButton('clearFilters');
258+
const getContext = renderWithContext();
270259

271-
fireEvent.click(button);
260+
act(() => {
261+
getContext().clearFilters();
262+
});
272263

273264
expect(saveStateSpy).toHaveBeenCalledWith({
274265
auth: {
@@ -286,4 +277,96 @@ describe('renderer/context/App.tsx', () => {
286277
});
287278
});
288279
});
280+
281+
describe('authentication functions', () => {
282+
const addAccountSpy = jest
283+
.spyOn(authUtils, 'addAccount')
284+
.mockImplementation(jest.fn());
285+
const removeAccountSpy = jest.spyOn(authUtils, 'removeAccount');
286+
287+
beforeEach(() => {
288+
jest.clearAllMocks();
289+
});
290+
291+
it('loginWithDeviceFlowStart calls startGitHubDeviceFlow', async () => {
292+
const startGitHubDeviceFlowSpy = jest
293+
.spyOn(authUtils, 'startGitHubDeviceFlow')
294+
.mockImplementation(jest.fn());
295+
296+
const getContext = renderWithContext();
297+
298+
act(() => {
299+
getContext().loginWithDeviceFlowStart();
300+
});
301+
302+
expect(startGitHubDeviceFlowSpy).toHaveBeenCalled();
303+
});
304+
305+
it('loginWithDeviceFlowPoll calls pollGitHubDeviceFlow', async () => {
306+
const pollGitHubDeviceFlowSpy = jest
307+
.spyOn(authUtils, 'pollGitHubDeviceFlow')
308+
.mockImplementation(jest.fn());
309+
310+
const getContext = renderWithContext();
311+
312+
act(() => {
313+
getContext().loginWithDeviceFlowPoll(
314+
'session' as unknown as DeviceFlowSession,
315+
);
316+
});
317+
318+
expect(pollGitHubDeviceFlowSpy).toHaveBeenCalledWith('session');
319+
});
320+
321+
it('loginWithDeviceFlowComplete calls addAccount', async () => {
322+
const getContext = renderWithContext();
323+
324+
act(() => {
325+
getContext().loginWithDeviceFlowComplete(
326+
'token' as Token,
327+
'github.com' as Hostname,
328+
);
329+
});
330+
331+
expect(addAccountSpy).toHaveBeenCalledWith(
332+
expect.anything(),
333+
'GitHub App',
334+
'token',
335+
'github.com',
336+
);
337+
});
338+
339+
it('loginWithOAuthApp calls performGitHubWebOAuth', async () => {
340+
const performGitHubWebOAuthSpy = jest.spyOn(
341+
authUtils,
342+
'performGitHubWebOAuth',
343+
);
344+
345+
const getContext = renderWithContext();
346+
347+
act(() => {
348+
getContext().loginWithOAuthApp({
349+
clientId: 'id' as ClientID,
350+
clientSecret: 'secret' as ClientSecret,
351+
hostname: 'github.com' as Hostname,
352+
});
353+
});
354+
355+
expect(performGitHubWebOAuthSpy).toHaveBeenCalled();
356+
});
357+
358+
it('logoutFromAccount calls removeAccountNotifications, removeAccount', async () => {
359+
const getContext = renderWithContext();
360+
361+
getContext().logoutFromAccount(mockGitHubCloudAccount);
362+
363+
expect(removeAccountNotificationsMock).toHaveBeenCalledWith(
364+
mockGitHubCloudAccount,
365+
);
366+
expect(removeAccountSpy).toHaveBeenCalledWith(
367+
expect.anything(),
368+
mockGitHubCloudAccount,
369+
);
370+
});
371+
});
289372
});

0 commit comments

Comments
 (0)