11/* @vitest -environment jsdom */
22import { renderHook , waitFor } from "@testing-library/react" ;
3- import { beforeEach , describe , expect , it , vi } from "vitest" ;
3+ import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
44import { useProjects } from "./useProjects" ;
55
6- const callToolMock = vi . fn ( ) ;
7- vi . mock ( "../api/rpc" , ( ) => ( {
8- callTool : ( ...args : unknown [ ] ) => callToolMock ( ...args ) ,
9- } ) ) ;
10-
6+ const fetchMock = vi . fn ( ) ;
117describe ( "useProjects machine-readable pagination" , ( ) => {
12- beforeEach ( ( ) => callToolMock . mockReset ( ) ) ;
8+ beforeEach ( ( ) => {
9+ fetchMock . mockReset ( ) ;
10+ vi . stubGlobal ( "fetch" , fetchMock ) ;
11+ } ) ;
12+
13+ afterEach ( ( ) => vi . unstubAllGlobals ( ) ) ;
1314
1415 it ( "requests JSON and merges every project and schema page" , async ( ) => {
15- callToolMock . mockImplementation ( async ( name : string , args : Record < string , unknown > ) => {
16- if ( name === "list_projects" ) {
17- if ( args . offset === 0 ) {
16+ fetchMock . mockImplementation ( async ( input : string ) => {
17+ const [ name , query ] = input . slice ( 5 ) . split ( "?" ) ;
18+ const args = Object . fromEntries ( new URLSearchParams ( query ) ) ;
19+ const page = await ( async ( ) => {
20+ if ( name === "projects" ) {
21+ if ( args . offset === "0" ) {
22+ return {
23+ projects : [ { name : "alpha" , root_path : "/alpha" , indexed_at : "now" } ] ,
24+ has_more : true ,
25+ next_offset : 1 ,
26+ } ;
27+ }
1828 return {
19- projects : [ { name : "alpha" , root_path : "/alpha" , indexed_at : "now" } ] ,
20- has_more : true ,
21- next_offset : 1 ,
29+ projects : [ { name : "beta" , root_path : "/beta" , indexed_at : "now" } ] ,
30+ has_more : false ,
2231 } ;
2332 }
24- return {
25- projects : [ { name : "beta" , root_path : "/beta" , indexed_at : "now" } ] ,
26- has_more : false ,
27- } ;
28- }
29- if ( name === "get_graph_schema" && args . project === "alpha" ) {
30- if ( args . offset === 0 ) {
33+ if ( name === "schema" && args . project === "alpha" ) {
34+ if ( args . offset === "0" ) {
35+ return {
36+ node_labels : [ { label : "Function" , count : 3 } ] ,
37+ edge_types : [ ] ,
38+ has_more : true ,
39+ next_offset : 1 ,
40+ } ;
41+ }
3142 return {
32- node_labels : [ { label : "Function" , count : 3 } ] ,
33- edge_types : [ ] ,
34- total_nodes : 3 ,
35- total_edges : 2 ,
36- has_more : true ,
37- next_offset : 1 ,
43+ node_labels : [ ] ,
44+ edge_types : [ { type : "CALLS" , count : 2 } ] ,
45+ has_more : false ,
3846 } ;
3947 }
4048 return {
41- node_labels : [ ] ,
42- edge_types : [ { type : "CALLS" , count : 2 } ] ,
43- total_nodes : 3 ,
44- total_edges : 2 ,
49+ node_labels : [ { label : "Class" , count : 1 } ] ,
50+ edge_types : [ ] ,
4551 has_more : false ,
4652 } ;
47- }
48- return {
49- node_labels : [ { label : "Class" , count : 1 } ] ,
50- edge_types : [ ] ,
51- total_nodes : 1 ,
52- total_edges : 0 ,
53- has_more : false ,
54- } ;
53+ } ) ( ) ;
54+ return { ok : true , json : async ( ) => page } ;
5555 } ) ;
5656
5757 const { result } = renderHook ( ( ) => useProjects ( ) ) ;
@@ -64,23 +64,21 @@ describe("useProjects machine-readable pagination", () => {
6464 expect ( result . current . projects [ 0 ] . schema ?. edge_types ) . toEqual ( [
6565 { type : "CALLS" , count : 2 } ,
6666 ] ) ;
67- expect ( callToolMock ) . toHaveBeenCalledWith ( "list_projects" , {
68- format : "json" ,
69- detail : "stats" ,
70- limit : 500 ,
71- offset : 0 ,
72- } ) ;
73- expect ( callToolMock ) . toHaveBeenCalledWith ( "list_projects" , {
74- format : "json" ,
75- detail : "stats" ,
76- limit : 500 ,
77- offset : 1 ,
78- } ) ;
79- expect ( callToolMock ) . toHaveBeenCalledWith ( "get_graph_schema" , {
80- project : "alpha" ,
81- format : "json" ,
82- limit : 500 ,
83- offset : 1 ,
67+ expect ( result . current . projects [ 0 ] . schema ?. total_nodes ) . toBe ( 3 ) ;
68+ expect ( result . current . projects [ 0 ] . schema ?. total_edges ) . toBe ( 2 ) ;
69+ expect ( fetchMock ) . toHaveBeenCalledWith ( "/api/projects?limit=500&offset=0" ) ;
70+ expect ( fetchMock ) . toHaveBeenCalledWith ( "/api/projects?limit=500&offset=1" ) ;
71+ expect ( fetchMock ) . toHaveBeenCalledWith ( "/api/schema?project=alpha&limit=500&offset=1" ) ;
72+ } ) ;
73+ it ( "reports native API errors" , async ( ) => {
74+ fetchMock . mockResolvedValue ( {
75+ ok : false ,
76+ status : 400 ,
77+ json : async ( ) => ( { error : "cannot read cache directory" } ) ,
8478 } ) ;
79+ const { result } = renderHook ( ( ) => useProjects ( ) ) ;
80+ await waitFor ( ( ) => expect ( result . current . loading ) . toBe ( false ) ) ;
81+ expect ( result . current . error ) . toBe ( "cannot read cache directory" ) ;
82+ expect ( result . current . projects ) . toEqual ( [ ] ) ;
8583 } ) ;
8684} ) ;
0 commit comments