@@ -17,7 +17,10 @@ describe("configureWikiTools", () => {
1717 let server : McpServer ;
1818 let tokenProvider : TokenProviderMock ;
1919 let connectionProvider : ConnectionProviderMock ;
20- let mockConnection : { getWikiApi : jest . Mock } ;
20+ let mockConnection : {
21+ getWikiApi : jest . Mock ;
22+ serverUrl : string ;
23+ } ;
2124 let mockWikiApi : WikiApiMock ;
2225
2326 beforeEach ( ( ) => {
@@ -31,6 +34,7 @@ describe("configureWikiTools", () => {
3134 } ;
3235 mockConnection = {
3336 getWikiApi : jest . fn ( ) . mockResolvedValue ( mockWikiApi ) ,
37+ serverUrl : "https://dev.azure.com/testorg" ,
3438 } ;
3539 connectionProvider = jest . fn ( ) . mockResolvedValue ( mockConnection ) ;
3640 } ) ;
@@ -502,7 +506,7 @@ describe("configureWikiTools", () => {
502506
503507 // Mock fetch for REST page by id returning content
504508 const mockFetch = jest . fn ( ) ;
505- global . fetch = mockFetch as any ;
509+ global . fetch = mockFetch as typeof fetch ;
506510 mockFetch . mockResolvedValueOnce ( {
507511 ok : true ,
508512 json : jest . fn ( ) . mockResolvedValue ( { content : "# Page Title\nBody" } ) ,
@@ -512,7 +516,7 @@ describe("configureWikiTools", () => {
512516 const result = await handler ( { url } ) ;
513517
514518 // Current implementation may fallback to root path stream retrieval
515- expect ( mockWikiApi . getPageText ) . toHaveBeenCalledWith ( "project" , "myWiki" , "/" , undefined , undefined , true ) ;
519+ expect ( mockWikiApi . getPageText ) . not . toHaveBeenCalled ( ) ;
516520 // Content either direct or from stream JSON string wrapping
517521 expect ( result . content [ 0 ] . text ) . toContain ( "Page Title" ) ;
518522 } ) ;
@@ -525,7 +529,7 @@ describe("configureWikiTools", () => {
525529 ( tokenProvider as jest . Mock ) . mockResolvedValueOnce ( { token : "abc" , expiresOnTimestamp : Date . now ( ) + 10000 } ) ;
526530
527531 const mockFetch = jest . fn ( ) ;
528- global . fetch = mockFetch as any ;
532+ global . fetch = mockFetch as typeof fetch ;
529533 mockFetch . mockResolvedValueOnce ( {
530534 ok : true ,
531535 json : jest . fn ( ) . mockResolvedValue ( { path : "/Some/Page" } ) ,
@@ -545,7 +549,7 @@ describe("configureWikiTools", () => {
545549 const result = await handler ( { url } ) ;
546550
547551 // Implementation currently falls back to root path if path not resolved prior to fallback
548- expect ( mockWikiApi . getPageText ) . toHaveBeenCalledWith ( "project" , "myWiki" , "/" , undefined , undefined , true ) ;
552+ expect ( mockWikiApi . getPageText ) . toHaveBeenCalledWith ( "project" , "myWiki" , "/Some/Page " , undefined , undefined , true ) ;
549553 expect ( result . content [ 0 ] . text ) . toBe ( '"fallback content"' ) ;
550554 } ) ;
551555
@@ -579,6 +583,120 @@ describe("configureWikiTools", () => {
579583 expect ( result . isError ) . toBe ( true ) ;
580584 expect ( result . content [ 0 ] . text ) . toContain ( "Error fetching wiki page content: URL does not match expected wiki pattern" ) ;
581585 } ) ;
586+
587+ it ( "should handle invalid URL format" , async ( ) => {
588+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
589+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
590+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
591+ const [ , , , handler ] = call ;
592+
593+ const result = await handler ( { url : "not-a-valid-url" } ) ;
594+ expect ( result . isError ) . toBe ( true ) ;
595+ expect ( result . content [ 0 ] . text ) . toContain ( "Error fetching wiki page content: Invalid URL format" ) ;
596+ } ) ;
597+
598+ it ( "should handle URL with pageId that returns 404" , async ( ) => {
599+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
600+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
601+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
602+ const [ , , , handler ] = call ;
603+
604+ ( tokenProvider as jest . Mock ) . mockResolvedValueOnce ( { token : "abc" , expiresOnTimestamp : Date . now ( ) + 10000 } ) ;
605+
606+ const mockFetch = jest . fn ( ) ;
607+ global . fetch = mockFetch as unknown as typeof fetch ;
608+ mockFetch . mockResolvedValueOnce ( {
609+ ok : false ,
610+ status : 404 ,
611+ } ) ;
612+
613+ const url = "https://dev.azure.com/org/project/_wiki/wikis/myWiki/999/NonExistent-Page" ;
614+ const result = await handler ( { url } ) ;
615+
616+ expect ( result . isError ) . toBe ( true ) ;
617+ expect ( result . content [ 0 ] . text ) . toContain ( "Error fetching wiki page content: Page with id 999 not found" ) ;
618+ } ) ;
619+
620+ it ( "should handle URL that resolves but project/wiki end up undefined" , async ( ) => {
621+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
622+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
623+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
624+ const [ , , , handler ] = call ;
625+
626+ const url = "https://dev.azure.com/org//_wiki/wikis/?pagePath=%2FHome" ;
627+ const result = await handler ( { url } ) ;
628+
629+ expect ( result . isError ) . toBe ( true ) ;
630+ expect ( result . content [ 0 ] . text ) . toContain ( "Error fetching wiki page content: Could not extract project or wikiIdentifier from URL" ) ;
631+ } ) ;
632+
633+ it ( "should handle URL with non-numeric pageId" , async ( ) => {
634+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
635+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
636+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
637+ const [ , , , handler ] = call ;
638+
639+ const mockStream = {
640+ setEncoding : jest . fn ( ) ,
641+ on : function ( event : string , cb : ( chunk ?: unknown ) => void ) {
642+ if ( event === "data" ) setImmediate ( ( ) => cb ( "content for non-numeric path" ) ) ;
643+ if ( event === "end" ) setImmediate ( ( ) => cb ( ) ) ;
644+ return this ;
645+ } ,
646+ } ;
647+ mockWikiApi . getPageText . mockResolvedValue ( mockStream as unknown ) ;
648+
649+ const url = "https://dev.azure.com/org/project/_wiki/wikis/myWiki/not-a-number/Some-Page" ;
650+ const result = await handler ( { url } ) ;
651+
652+ expect ( mockWikiApi . getPageText ) . toHaveBeenCalledWith ( "project" , "myWiki" , "/" , undefined , undefined , true ) ;
653+ expect ( result . content [ 0 ] . text ) . toBe ( '"content for non-numeric path"' ) ;
654+ } ) ;
655+
656+ it ( "should use default root path when resolvedPath is undefined" , async ( ) => {
657+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
658+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
659+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
660+ const [ , , , handler ] = call ;
661+
662+ const mockStream = {
663+ setEncoding : jest . fn ( ) ,
664+ on : function ( event : string , cb : ( chunk ?: unknown ) => void ) {
665+ if ( event === "data" ) setImmediate ( ( ) => cb ( "root page content" ) ) ;
666+ if ( event === "end" ) setImmediate ( ( ) => cb ( ) ) ;
667+ return this ;
668+ } ,
669+ } ;
670+ mockWikiApi . getPageText . mockResolvedValue ( mockStream as unknown ) ;
671+
672+ const result = await handler ( { wikiIdentifier : "wiki1" , project : "project1" } ) ;
673+
674+ expect ( mockWikiApi . getPageText ) . toHaveBeenCalledWith ( "project1" , "wiki1" , "/" , undefined , undefined , true ) ;
675+ expect ( result . content [ 0 ] . text ) . toBe ( '"root page content"' ) ;
676+ expect ( result . isError ) . toBeUndefined ( ) ;
677+ } ) ;
678+
679+ it ( "should handle scenario where resolvedProject/Wiki become null after URL processing" , async ( ) => {
680+ configureWikiTools ( server , tokenProvider , connectionProvider ) ;
681+ const call = ( server . tool as jest . Mock ) . mock . calls . find ( ( [ toolName ] ) => toolName === "wiki_get_page_content" ) ;
682+ if ( ! call ) throw new Error ( "wiki_get_page_content tool not registered" ) ;
683+ const [ , , , handler ] = call ;
684+
685+ ( tokenProvider as jest . Mock ) . mockResolvedValueOnce ( { token : "abc" , expiresOnTimestamp : Date . now ( ) + 10000 } ) ;
686+
687+ const mockFetch = jest . fn ( ) ;
688+ global . fetch = mockFetch as unknown as typeof fetch ;
689+ mockFetch . mockResolvedValueOnce ( {
690+ ok : false ,
691+ status : 404 ,
692+ } ) ;
693+
694+ const url = "https://dev.azure.com//_wiki/wikis//123/Page" ;
695+ const result = await handler ( { url } ) ;
696+
697+ expect ( result . isError ) . toBe ( true ) ;
698+ expect ( result . content [ 0 ] . text ) . toContain ( "URL does not match expected wiki pattern" ) ;
699+ } ) ;
582700 } ) ;
583701
584702 describe ( "create_or_update_page tool" , ( ) => {
0 commit comments