@@ -5,7 +5,10 @@ const apiMocks = vi.hoisted(() => ({
55 getTwistClient : vi . fn ( ) ,
66} ) )
77
8- vi . mock ( '../lib/api.js' , ( ) => apiMocks )
8+ vi . mock ( '../lib/api.js' , async ( importOriginal ) => ( {
9+ ...( await importOriginal < typeof import ( '../lib/api.js' ) > ( ) ) ,
10+ getTwistClient : apiMocks . getTwistClient ,
11+ } ) )
912
1013vi . mock ( '../lib/public-channels.js' , ( ) => ( {
1114 assertChannelIsPublic : vi . fn ( ) ,
@@ -76,7 +79,10 @@ function createClient({
7679 if ( options ?. batch ) return { kind : 'comments' }
7780 return Promise . resolve ( comments )
7881 } ) ,
79- getComment : vi . fn ( ) ,
82+ getComment : vi . fn ( ( _id : number , options ?: { batch ?: boolean } ) => {
83+ if ( options ?. batch ) return { kind : 'comment' , id : _id }
84+ return Promise . resolve ( undefined )
85+ } ) ,
8086 } ,
8187 channels : {
8288 getChannel : vi . fn ( ( _id : number , options ?: { batch ?: boolean } ) => {
@@ -97,11 +103,17 @@ function createClient({
97103 } ,
98104 batch : vi . fn ( async ( ...requests : Array < { kind : string ; id ?: number ; userId ?: number } > ) =>
99105 requests . map ( ( request ) => {
100- if ( request . kind === 'thread' ) return { data : thread }
101- if ( request . kind === 'comments' ) return { data : comments }
102- if ( request . kind === 'channel' ) return { data : channel }
106+ if ( request . kind === 'thread' ) return { code : 200 , data : thread }
107+ if ( request . kind === 'comments' ) return { code : 200 , data : comments }
108+ if ( request . kind === 'comment' )
109+ return {
110+ code : 200 ,
111+ data : comments . find ( ( c ) => c . id === request . id ) ?? comments [ 0 ] ,
112+ }
113+ if ( request . kind === 'channel' ) return { code : 200 , data : channel }
103114 if ( request . kind === 'user' && request . userId ) {
104115 return {
116+ code : 200 ,
105117 data : users [ request . userId ] ?? {
106118 id : request . userId ,
107119 name : `user:${ request . userId } ` ,
@@ -303,3 +315,49 @@ describe('thread view --unread', () => {
303315 consoleSpy . mockRestore ( )
304316 } )
305317} )
318+
319+ describe ( 'thread view with failed batch response' , ( ) => {
320+ beforeEach ( ( ) => {
321+ vi . resetAllMocks ( )
322+ } )
323+
324+ it ( 'throws a clear error when comment batch response fails' , async ( ) => {
325+ const client = createClient ( {
326+ users : { 1 : { id : 1 , name : 'Alice' } } ,
327+ } )
328+ // Override batch to return a 404 for the comment
329+ client . batch . mockResolvedValueOnce ( [
330+ { code : 200 , data : createThread ( 500 ) } ,
331+ { code : 404 , data : null as never } ,
332+ ] )
333+ apiMocks . getTwistClient . mockResolvedValue ( client )
334+
335+ const program = createProgram ( )
336+ const consoleSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } )
337+
338+ await expect (
339+ program . parseAsync ( [ 'node' , 'tw' , 'thread' , 'view' , '500' , '--comment' , '99999' ] ) ,
340+ ) . rejects . toThrow ( 'Failed to fetch comment 99999.' )
341+
342+ consoleSpy . mockRestore ( )
343+ } )
344+
345+ it ( 'throws a clear error when thread batch response fails' , async ( ) => {
346+ const client = createClient ( )
347+ // Override batch to return a 404 for the thread
348+ client . batch . mockResolvedValueOnce ( [
349+ { code : 404 , data : null as never } ,
350+ { code : 200 , data : [ ] } ,
351+ ] )
352+ apiMocks . getTwistClient . mockResolvedValue ( client )
353+
354+ const program = createProgram ( )
355+ const consoleSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } )
356+
357+ await expect ( program . parseAsync ( [ 'node' , 'tw' , 'thread' , 'view' , '500' ] ) ) . rejects . toThrow (
358+ 'Failed to fetch thread.' ,
359+ )
360+
361+ consoleSpy . mockRestore ( )
362+ } )
363+ } )
0 commit comments