@@ -12,11 +12,44 @@ import * as comms from '../utils/comms';
1212import * as notifications from '../utils/notifications/notifications' ;
1313import * as storage from '../utils/storage' ;
1414import * as tray from '../utils/tray' ;
15- import { AppContext , AppProvider } from './App' ;
15+ import { AppContext , type AppContextState , AppProvider } from './App' ;
1616import { defaultSettings } from './defaults' ;
1717
1818jest . mock ( '../hooks/useNotifications' ) ;
1919
20+ // Helper to render a button that calls a context method when clicked
21+ const renderContextButton = (
22+ contextMethodName : keyof AppContextState ,
23+ ...args : unknown [ ]
24+ ) => {
25+ const TestComponent = ( ) => {
26+ const context = useContext ( AppContext ) ;
27+ const method = context [ contextMethodName ] ;
28+ return (
29+ < button
30+ data-testid = "context-method-button"
31+ onClick = { ( ) => {
32+ if ( typeof method === 'function' ) {
33+ ( method as ( ...args : unknown [ ] ) => void ) ( ...args ) ;
34+ }
35+ } }
36+ type = "button"
37+ >
38+ { String ( contextMethodName ) }
39+ </ button >
40+ ) ;
41+ } ;
42+
43+ const result = renderWithAppContext (
44+ < AppProvider >
45+ < TestComponent />
46+ </ AppProvider > ,
47+ ) ;
48+
49+ const button = result . getByTestId ( 'context-method-button' ) ;
50+ return { ...result , button } ;
51+ } ;
52+
2053describe ( 'renderer/context/App.tsx' , ( ) => {
2154 beforeEach ( ( ) => {
2255 jest . useFakeTimers ( ) ;
@@ -28,7 +61,7 @@ describe('renderer/context/App.tsx', () => {
2861 } ) ;
2962
3063 describe ( 'notification methods' , ( ) => {
31- const mockSetTrayIconColorAndTitle = jest
64+ const setTrayIconColorAndTitleSpy = jest
3265 . spyOn ( tray , 'setTrayIconColorAndTitle' )
3366 . mockImplementation ( jest . fn ( ) ) ;
3467
@@ -93,117 +126,59 @@ describe('renderer/context/App.tsx', () => {
93126 } ) ;
94127
95128 it ( 'should call fetchNotifications' , async ( ) => {
96- const TestComponent = ( ) => {
97- const { fetchNotifications } = useContext ( AppContext ) ;
98-
99- return (
100- < button onClick = { fetchNotifications } type = "button" >
101- Test Case
102- </ button >
103- ) ;
104- } ;
105-
106- const { getByText } = renderWithAppContext (
107- < AppProvider >
108- < TestComponent />
109- </ AppProvider > ,
110- ) ;
129+ const { button } = renderContextButton ( 'fetchNotifications' ) ;
111130
112131 mockFetchNotifications . mockReset ( ) ;
113132
114- fireEvent . click ( getByText ( 'Test Case' ) ) ;
133+ fireEvent . click ( button ) ;
115134
116135 expect ( mockFetchNotifications ) . toHaveBeenCalledTimes ( 1 ) ;
117136 } ) ;
118137
119138 it ( 'should call markNotificationsAsRead' , async ( ) => {
120- const TestComponent = ( ) => {
121- const { markNotificationsAsRead } = useContext ( AppContext ) ;
122-
123- return (
124- < button
125- onClick = { ( ) => markNotificationsAsRead ( [ mockSingleNotification ] ) }
126- type = "button"
127- >
128- Test Case
129- </ button >
130- ) ;
131- } ;
132-
133- const { getByText } = renderWithAppContext (
134- < AppProvider >
135- < TestComponent />
136- </ AppProvider > ,
137- ) ;
139+ const { button } = renderContextButton ( 'markNotificationsAsRead' , [
140+ mockSingleNotification ,
141+ ] ) ;
138142
139- fireEvent . click ( getByText ( 'Test Case' ) ) ;
143+ fireEvent . click ( button ) ;
140144
141145 expect ( mockMarkNotificationsAsRead ) . toHaveBeenCalledTimes ( 1 ) ;
142146 expect ( mockMarkNotificationsAsRead ) . toHaveBeenCalledWith (
143147 mockDefaultState ,
144148 [ mockSingleNotification ] ,
145149 ) ;
146- expect ( mockSetTrayIconColorAndTitle ) . toHaveBeenCalledTimes ( 1 ) ;
150+ expect ( setTrayIconColorAndTitleSpy ) . toHaveBeenCalledTimes ( 1 ) ;
147151 } ) ;
148152
149153 it ( 'should call markNotificationsAsDone' , async ( ) => {
150- const TestComponent = ( ) => {
151- const { markNotificationsAsDone } = useContext ( AppContext ) ;
152-
153- return (
154- < button
155- onClick = { ( ) => markNotificationsAsDone ( [ mockSingleNotification ] ) }
156- type = "button"
157- >
158- Test Case
159- </ button >
160- ) ;
161- } ;
162-
163- const { getByText } = renderWithAppContext (
164- < AppProvider >
165- < TestComponent />
166- </ AppProvider > ,
167- ) ;
154+ const { button } = renderContextButton ( 'markNotificationsAsDone' , [
155+ mockSingleNotification ,
156+ ] ) ;
168157
169- fireEvent . click ( getByText ( 'Test Case' ) ) ;
158+ fireEvent . click ( button ) ;
170159
171160 expect ( mockMarkNotificationsAsDone ) . toHaveBeenCalledTimes ( 1 ) ;
172161 expect ( mockMarkNotificationsAsDone ) . toHaveBeenCalledWith (
173162 mockDefaultState ,
174163 [ mockSingleNotification ] ,
175164 ) ;
176- expect ( mockSetTrayIconColorAndTitle ) . toHaveBeenCalledTimes ( 1 ) ;
165+ expect ( setTrayIconColorAndTitleSpy ) . toHaveBeenCalledTimes ( 1 ) ;
177166 } ) ;
178167
179168 it ( 'should call unsubscribeNotification' , async ( ) => {
180- const TestComponent = ( ) => {
181- const { unsubscribeNotification } = useContext ( AppContext ) ;
182-
183- return (
184- < button
185- onClick = { ( ) => unsubscribeNotification ( mockSingleNotification ) }
186- type = "button"
187- >
188- Test Case
189- </ button >
190- ) ;
191- } ;
192-
193- const { getByText } = renderWithAppContext (
194- < AppProvider >
195- < TestComponent />
196- </ AppProvider > ,
169+ const { button } = renderContextButton (
170+ 'unsubscribeNotification' ,
171+ mockSingleNotification ,
197172 ) ;
198173
199- fireEvent . click ( getByText ( 'Test Case' ) ) ;
174+ fireEvent . click ( button ) ;
200175
201176 expect ( mockUnsubscribeNotification ) . toHaveBeenCalledTimes ( 1 ) ;
202177 expect ( mockUnsubscribeNotification ) . toHaveBeenCalledWith (
203178 mockDefaultState ,
204179 mockSingleNotification ,
205180 ) ;
206- expect ( mockSetTrayIconColorAndTitle ) . toHaveBeenCalledTimes ( 1 ) ;
181+ expect ( setTrayIconColorAndTitleSpy ) . toHaveBeenCalledTimes ( 1 ) ;
207182 } ) ;
208183 } ) ;
209184
@@ -224,31 +199,12 @@ describe('renderer/context/App.tsx', () => {
224199 it ( 'should call loginWithPersonalAccessToken' , async ( ) => {
225200 apiRequestAuthSpy . mockResolvedValueOnce ( null ) ;
226201
227- const TestComponent = ( ) => {
228- const { loginWithPersonalAccessToken } = useContext ( AppContext ) ;
229-
230- return (
231- < button
232- onClick = { ( ) =>
233- loginWithPersonalAccessToken ( {
234- hostname : 'github.com' as Hostname ,
235- token : '123-456' as Token ,
236- } )
237- }
238- type = "button"
239- >
240- Test Case
241- </ button >
242- ) ;
243- } ;
244-
245- const { getByText } = renderWithAppContext (
246- < AppProvider >
247- < TestComponent />
248- </ AppProvider > ,
249- ) ;
202+ const { button } = renderContextButton ( 'loginWithPersonalAccessToken' , {
203+ hostname : 'github.com' as Hostname ,
204+ token : '123-456' as Token ,
205+ } ) ;
250206
251- fireEvent . click ( getByText ( 'Test Case' ) ) ;
207+ fireEvent . click ( button ) ;
252208
253209 await waitFor ( ( ) =>
254210 expect ( mockFetchNotifications ) . toHaveBeenCalledTimes ( 1 ) ,
@@ -277,27 +233,14 @@ describe('renderer/context/App.tsx', () => {
277233 . spyOn ( storage , 'saveState' )
278234 . mockImplementation ( jest . fn ( ) ) ;
279235
280- const TestComponent = ( ) => {
281- const { updateSetting } = useContext ( AppContext ) ;
282-
283- return (
284- < button
285- onClick = { ( ) => updateSetting ( 'participating' , true ) }
286- type = "button"
287- >
288- Test Case
289- </ button >
290- ) ;
291- } ;
292-
293- const { getByText } = renderWithAppContext (
294- < AppProvider >
295- < TestComponent />
296- </ AppProvider > ,
236+ const { button } = renderContextButton (
237+ 'updateSetting' ,
238+ 'participating' ,
239+ true ,
297240 ) ;
298241
299242 act ( ( ) => {
300- fireEvent . click ( getByText ( 'Test Case' ) ) ;
243+ fireEvent . click ( button ) ;
301244 } ) ;
302245
303246 expect ( mockSaveState ) . toHaveBeenCalledWith ( {
@@ -313,36 +256,23 @@ describe('renderer/context/App.tsx', () => {
313256
314257 it ( 'should call updateSetting and set auto launch(openAtStartup)' , async ( ) => {
315258 const setAutoLaunchSpy = jest . spyOn ( comms , 'setAutoLaunch' ) ;
316- const mockSaveState = jest
259+ const saveStateSpy = jest
317260 . spyOn ( storage , 'saveState' )
318261 . mockImplementation ( jest . fn ( ) ) ;
319262
320- const TestComponent = ( ) => {
321- const { updateSetting } = useContext ( AppContext ) ;
322-
323- return (
324- < button
325- onClick = { ( ) => updateSetting ( 'openAtStartup' , true ) }
326- type = "button"
327- >
328- Test Case
329- </ button >
330- ) ;
331- } ;
332-
333- const { getByText } = renderWithAppContext (
334- < AppProvider >
335- < TestComponent />
336- </ AppProvider > ,
263+ const { button } = renderContextButton (
264+ 'updateSetting' ,
265+ 'openAtStartup' ,
266+ true ,
337267 ) ;
338268
339269 act ( ( ) => {
340- fireEvent . click ( getByText ( 'Test Case' ) ) ;
270+ fireEvent . click ( button ) ;
341271 } ) ;
342272
343273 expect ( setAutoLaunchSpy ) . toHaveBeenCalledWith ( true ) ;
344274
345- expect ( mockSaveState ) . toHaveBeenCalledWith ( {
275+ expect ( saveStateSpy ) . toHaveBeenCalledWith ( {
346276 auth : {
347277 accounts : [ ] ,
348278 } as AuthState ,
@@ -354,31 +284,17 @@ describe('renderer/context/App.tsx', () => {
354284 } ) ;
355285
356286 it ( 'should clear filters back to default' , async ( ) => {
357- const mockSaveState = jest
287+ const saveStateSpy = jest
358288 . spyOn ( storage , 'saveState' )
359289 . mockImplementation ( jest . fn ( ) ) ;
360290
361- const TestComponent = ( ) => {
362- const { clearFilters } = useContext ( AppContext ) ;
363-
364- return (
365- < button onClick = { ( ) => clearFilters ( ) } type = "button" >
366- Test Case
367- </ button >
368- ) ;
369- } ;
370-
371- const { getByText } = renderWithAppContext (
372- < AppProvider >
373- < TestComponent />
374- </ AppProvider > ,
375- ) ;
291+ const { button } = renderContextButton ( 'clearFilters' ) ;
376292
377293 act ( ( ) => {
378- fireEvent . click ( getByText ( 'Test Case' ) ) ;
294+ fireEvent . click ( button ) ;
379295 } ) ;
380296
381- expect ( mockSaveState ) . toHaveBeenCalledWith ( {
297+ expect ( saveStateSpy ) . toHaveBeenCalledWith ( {
382298 auth : {
383299 accounts : [ ] ,
384300 } as AuthState ,
@@ -395,31 +311,17 @@ describe('renderer/context/App.tsx', () => {
395311 } ) ;
396312
397313 it ( 'should call resetSettings' , async ( ) => {
398- const mockSaveState = jest
314+ const saveStateSpy = jest
399315 . spyOn ( storage , 'saveState' )
400316 . mockImplementation ( jest . fn ( ) ) ;
401317
402- const TestComponent = ( ) => {
403- const { resetSettings } = useContext ( AppContext ) ;
404-
405- return (
406- < button onClick = { ( ) => resetSettings ( ) } type = "button" >
407- Test Case
408- </ button >
409- ) ;
410- } ;
411-
412- const { getByText } = renderWithAppContext (
413- < AppProvider >
414- < TestComponent />
415- </ AppProvider > ,
416- ) ;
318+ const { button } = renderContextButton ( 'resetSettings' ) ;
417319
418320 act ( ( ) => {
419- fireEvent . click ( getByText ( 'Test Case' ) ) ;
321+ fireEvent . click ( button ) ;
420322 } ) ;
421323
422- expect ( mockSaveState ) . toHaveBeenCalledWith ( {
324+ expect ( saveStateSpy ) . toHaveBeenCalledWith ( {
423325 auth : {
424326 accounts : [ ] ,
425327 } as AuthState ,
0 commit comments