@@ -47,6 +47,20 @@ describe('googleDocsConnector', () => {
4747 } )
4848
4949 describe ( 'getDocument' , ( ) => {
50+ it . each ( [ { } , { ...DRIVE_FILE , id : 'different-document' } ] ) (
51+ 'rejects malformed Drive metadata instead of replacing retained content' ,
52+ async ( metadata ) => {
53+ vi . stubGlobal (
54+ 'fetch' ,
55+ vi . fn ( async ( ) => new Response ( JSON . stringify ( metadata ) , { status : 200 } ) )
56+ )
57+
58+ await expect (
59+ googleDocsConnector . getDocument ( ACCESS_TOKEN , { } , DOCUMENT_ID )
60+ ) . rejects . toThrow ( 'Google Drive API returned malformed file metadata' )
61+ }
62+ )
63+
5064 it ( 'authoritatively skips a listed document that changed type' , async ( ) => {
5165 vi . stubGlobal (
5266 'fetch' ,
@@ -257,6 +271,42 @@ describe('googleDocsConnector', () => {
257271 } )
258272 } )
259273
274+ it ( 'rejects a successful response that omits the required tabs array' , async ( ) => {
275+ stubFetchDocument ( new Response ( '{}' , { status : 200 } ) )
276+
277+ await expect ( googleDocsConnector . getDocument ( ACCESS_TOKEN , { } , DOCUMENT_ID ) ) . rejects . toThrow (
278+ 'Google Docs API returned a malformed document response'
279+ )
280+ } )
281+
282+ it ( 'rejects an empty tab object instead of replacing retained content' , async ( ) => {
283+ stubFetchDocument ( new Response ( JSON . stringify ( { tabs : [ { } ] } ) , { status : 200 } ) )
284+
285+ await expect ( googleDocsConnector . getDocument ( ACCESS_TOKEN , { } , DOCUMENT_ID ) ) . rejects . toThrow (
286+ 'Google Docs API returned a malformed document response'
287+ )
288+ } )
289+
290+ it ( 'rejects malformed nested tab content instead of dropping it' , async ( ) => {
291+ stubFetchDocument (
292+ new Response (
293+ JSON . stringify ( {
294+ tabs : [
295+ {
296+ documentTab : { body : { content : [ ] } } ,
297+ childTabs : [ { } ] ,
298+ } ,
299+ ] ,
300+ } ) ,
301+ { status : 200 }
302+ )
303+ )
304+
305+ await expect ( googleDocsConnector . getDocument ( ACCESS_TOKEN , { } , DOCUMENT_ID ) ) . rejects . toThrow (
306+ 'Google Docs API returned a malformed document response'
307+ )
308+ } )
309+
260310 it ( 'maps an oversized chunked hydration response to a visible skip' , async ( ) => {
261311 const chunk = new Uint8Array ( 34 * 1024 * 1024 )
262312 let chunksSent = 0
@@ -473,6 +523,46 @@ describe('googleDocsConnector', () => {
473523 } )
474524
475525 describe ( 'listDocuments' , ( ) => {
526+ it ( 'rejects a malformed successful Drive list envelope' , async ( ) => {
527+ vi . stubGlobal ( 'fetch' , vi . fn ( ) . mockResolvedValue ( new Response ( '{}' , { status : 200 } ) ) )
528+
529+ await expect (
530+ googleDocsConnector . listDocuments ( ACCESS_TOKEN , { } , undefined , { } )
531+ ) . rejects . toThrow ( 'Google Drive API returned malformed file-list metadata' )
532+ } )
533+
534+ it ( 'accepts a discriminator-only empty Drive list envelope' , async ( ) => {
535+ vi . stubGlobal (
536+ 'fetch' ,
537+ vi
538+ . fn ( )
539+ . mockResolvedValue (
540+ new Response ( JSON . stringify ( { kind : 'drive#fileList' } ) , { status : 200 } )
541+ )
542+ )
543+
544+ await expect (
545+ googleDocsConnector . listDocuments ( ACCESS_TOKEN , { } , undefined , { } )
546+ ) . resolves . toMatchObject ( { documents : [ ] , hasMore : false } )
547+ } )
548+
549+ it . each ( [
550+ {
551+ files : [ { name : 'Missing ID' , mimeType : DRIVE_FILE . mimeType , modifiedTime : '2026-01-01' } ] ,
552+ } ,
553+ { files : [ ] , nextPageToken : 123 } ,
554+ { files : [ ] , incompleteSearch : 'true' } ,
555+ ] ) ( 'rejects malformed Drive list metadata' , async ( body ) => {
556+ vi . stubGlobal (
557+ 'fetch' ,
558+ vi . fn ( ) . mockResolvedValue ( new Response ( JSON . stringify ( body ) , { status : 200 } ) )
559+ )
560+
561+ await expect (
562+ googleDocsConnector . listDocuments ( ACCESS_TOKEN , { } , undefined , { } )
563+ ) . rejects . toThrow ( 'Google Drive API returned malformed file-list metadata' )
564+ } )
565+
476566 it ( 'does not issue another Drive request after a lowered cap is already exhausted' , async ( ) => {
477567 const fetchMock = vi . fn ( )
478568 vi . stubGlobal ( 'fetch' , fetchMock )
@@ -586,9 +676,7 @@ describe('googleDocsConnector', () => {
586676 async ( maxDocs ) => {
587677 const fetchMock = vi
588678 . fn ( )
589- . mockResolvedValue (
590- new Response ( JSON . stringify ( { files : [ ] , nextPageToken : null } ) , { status : 200 } )
591- )
679+ . mockResolvedValue ( new Response ( JSON . stringify ( { files : [ ] } ) , { status : 200 } ) )
592680 vi . stubGlobal ( 'fetch' , fetchMock )
593681
594682 await expect (
0 commit comments