@@ -372,7 +372,7 @@ describe('utils', () => {
372372 logoutSpy . mockRestore ( ) ;
373373 } ) ;
374374
375- it ( 'catch block calls logout when secret is missing' , async ( ) => {
375+ it ( 'catch block calls logout when secret is missing (empty string) ' , async ( ) => {
376376 const consoleLogSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
377377 const consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
378378
@@ -381,7 +381,7 @@ describe('utils', () => {
381381 key === 'loginSalt' ? 'test-salt' : null
382382 ) ;
383383
384- // Mock service worker to return no secret
384+ // Mock service worker to return empty secret
385385 const postMessage = vi . fn ( ( msg : any ) => {
386386 if ( msg . type === MessageType . RequestSecret ) {
387387 triggerSWMessage ( { type : MessageType . RequestSecret , data : '' } ) ;
@@ -415,6 +415,98 @@ describe('utils', () => {
415415 consoleErrorSpy . mockRestore ( ) ;
416416 logoutSpy . mockRestore ( ) ;
417417 } ) ;
418+
419+ it ( 'catch block calls logout when secret is null' , async ( ) => {
420+ const consoleLogSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
421+ const consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
422+
423+ // Mock localStorage to return loginSalt
424+ ( window . localStorage . getItem as any ) . mockImplementation ( ( key : string ) =>
425+ key === 'loginSalt' ? 'test-salt' : null
426+ ) ;
427+
428+ // Mock service worker to return null secret
429+ const postMessage = vi . fn ( ( msg : any ) => {
430+ if ( msg . type === MessageType . RequestSecret ) {
431+ triggerSWMessage ( { type : MessageType . RequestSecret , data : null } ) ;
432+ }
433+ } ) ;
434+ withServiceWorker ( { postMessage } as any ) ;
435+
436+ // Mock fetchClient to throw an error
437+ const testError = new Error ( 'Network timeout' ) ;
438+ ( utils . fetchClient as any ) . GET = vi . fn ( async ( path : string ) => {
439+ if ( path === '/auth/jwt_refresh' ) {
440+ throw testError ;
441+ }
442+ return { error : null , response : { status : 200 } } ;
443+ } ) ;
444+
445+ // Mock logout function
446+ const logoutModule = await import ( '../components/Navbar' ) ;
447+ const logoutSpy = vi . spyOn ( logoutModule , 'logout' ) . mockImplementation ( async ( ) => { /* no-op */ } ) ;
448+
449+ await utils . refresh_access_token ( ) ;
450+
451+ // Verify logging
452+ expect ( consoleLogSpy ) . toHaveBeenCalledWith ( 'Failed to refresh access token:' , testError ) ;
453+ expect ( consoleErrorSpy ) . toHaveBeenCalledWith ( testError ) ;
454+
455+ // Verify logout was called
456+ expect ( logoutSpy ) . toHaveBeenCalledWith ( false ) ;
457+
458+ consoleLogSpy . mockRestore ( ) ;
459+ consoleErrorSpy . mockRestore ( ) ;
460+ logoutSpy . mockRestore ( ) ;
461+ } ) ;
462+
463+ it ( 'catch block calls logout when getSecretKeyFromServiceWorker times out' , async ( ) => {
464+ // Use fake timers to test timeout scenario
465+ vi . useFakeTimers ( ) ;
466+
467+ const consoleLogSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
468+ const consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { /* no-op */ } ) ;
469+
470+ // Mock localStorage to return loginSalt
471+ ( window . localStorage . getItem as any ) . mockImplementation ( ( key : string ) =>
472+ key === 'loginSalt' ? 'test-salt' : null
473+ ) ;
474+
475+ // Mock service worker that never responds
476+ const postMessage = vi . fn ( ) ; // No response triggered
477+ withServiceWorker ( { postMessage } as any ) ;
478+
479+ // Mock fetchClient to throw an error (triggers outer catch block)
480+ const testError = new Error ( 'Network timeout' ) ;
481+ ( utils . fetchClient as any ) . GET = vi . fn ( async ( path : string ) => {
482+ if ( path === '/auth/jwt_refresh' ) {
483+ throw testError ;
484+ }
485+ return { error : null , response : { status : 200 } } ;
486+ } ) ;
487+
488+ // Mock logout function
489+ const logoutModule = await import ( '../components/Navbar' ) ;
490+ const logoutSpy = vi . spyOn ( logoutModule , 'logout' ) . mockImplementation ( async ( ) => { /* no-op */ } ) ;
491+
492+ // Start refresh_access_token without awaiting
493+ const refreshPromise = utils . refresh_access_token ( ) ;
494+
495+ // Fast-forward time by 5000ms to trigger timeout in getSecretKeyFromServiceWorker
496+ await vi . advanceTimersByTimeAsync ( 5000 ) ;
497+
498+ // Now await the refresh to complete
499+ await refreshPromise ;
500+
501+ // Verify logout was called when getSecretKeyFromServiceWorker timed out
502+ expect ( logoutSpy ) . toHaveBeenCalledWith ( false ) ;
503+
504+ consoleLogSpy . mockRestore ( ) ;
505+ consoleErrorSpy . mockRestore ( ) ;
506+ logoutSpy . mockRestore ( ) ;
507+
508+ vi . useRealTimers ( ) ;
509+ } ) ;
418510 } ) ;
419511
420512 describe ( 'get_salt & get_salt_for_user' , ( ) => {
0 commit comments