@@ -549,6 +549,47 @@ describe('getFullDashboardData', () => {
549549 const result = await getFullDashboardData ( 'testuser' ) ;
550550 expect ( result . profile . joinedDate ) . toMatch ( / ^ [ A - Z a - z ] + \d { 4 } $ / ) ;
551551 } ) ;
552+
553+ it ( 'handles repos fetch failure gracefully' , async ( ) => {
554+ vi . mocked ( fetch ) . mockImplementation ( async ( url ) => {
555+ const urlStr = typeof url === 'string' ? url : ( url ?. toString ( ) ?? '' ) ;
556+
557+ // Repos fetch fails
558+ if ( urlStr . includes ( '/users/octocat/repos' ) ) {
559+ throw new Error ( 'Repos fetch failed' ) ;
560+ }
561+
562+ // Profile fetch succeeds
563+ if ( urlStr . includes ( '/users/octocat' ) ) {
564+ return mockResponse ( {
565+ login : 'octocat' ,
566+ name : 'The Octocat' ,
567+ avatar_url : 'avatar.png' ,
568+ public_repos : 10 ,
569+ followers : 20 ,
570+ following : 5 ,
571+ created_at : '2020-01-01T00:00:00Z' ,
572+ } ) ;
573+ }
574+
575+ // GraphQL contributions succeed
576+ return mockResponse ( {
577+ data : {
578+ user : {
579+ contributionsCollection : {
580+ contributionCalendar : mockCalendar ,
581+ } ,
582+ } ,
583+ } ,
584+ } ) ;
585+ } ) ;
586+
587+ const result = await getFullDashboardData ( 'octocat' ) ;
588+
589+ expect ( result ) . toBeDefined ( ) ;
590+ expect ( result . profile . stats . stars ) . toBe ( 0 ) ;
591+ expect ( result . languages ) . toEqual ( [ ] ) ;
592+ } ) ;
552593} ) ;
553594
554595describe ( 'GitHub API cache behavior' , ( ) => {
@@ -736,7 +777,7 @@ describe('getOrgDashboardData', () => {
736777
737778 it ( 'aggregates org data correctly' , async ( ) => {
738779 vi . mocked ( fetch ) . mockImplementation ( async ( url ) => {
739- const urlStr = url . toString ( ) ;
780+ const urlStr = typeof url === 'string' ? url : ( url ? .toString ( ) ?? '' ) ;
740781 if ( urlStr . includes ( '/orgs/vercel/members' ) ) return mockResponse ( [ { login : 'alice' } ] ) ;
741782 if ( urlStr . includes ( '/users/vercel/repos' ) ) return mockResponse ( [ { stargazers_count : 100 } ] ) ;
742783 if ( urlStr . includes ( '/users/vercel' ) )
@@ -761,7 +802,7 @@ describe('getOrgDashboardData', () => {
761802
762803 it ( 'throws an error if the target is a User instead of an Organization' , async ( ) => {
763804 vi . mocked ( fetch ) . mockImplementation ( async ( url ) => {
764- const urlStr = url . toString ( ) ;
805+ const urlStr = typeof url === 'string' ? url : ( url ? .toString ( ) ?? '' ) ;
765806 // Specifically catch the repos and members endpoints so they return valid arrays
766807 if ( urlStr . includes ( '/orgs/notanorg/members' ) ) return mockResponse ( [ ] ) ;
767808 if ( urlStr . includes ( '/users/notanorg/repos' ) ) return mockResponse ( [ ] ) ;
@@ -788,7 +829,7 @@ describe('getWrappedData', () => {
788829
789830 it ( 'returns wrapped statistics and top language correctly' , async ( ) => {
790831 vi . mocked ( fetch ) . mockImplementation ( async ( url ) => {
791- const urlStr = url . toString ( ) ;
832+ const urlStr = typeof url === 'string' ? url : ( url ? .toString ( ) ?? '' ) ;
792833 // Return 2 TS repos, 1 Rust repo
793834 if ( urlStr . includes ( '/repos' ) )
794835 return mockResponse ( [
0 commit comments