1
- import { describe , expect , it , vi } from "vitest" ;
2
1
import { EditorState } from "@codemirror/state" ;
3
2
import { EditorView } from "@codemirror/view" ;
3
+ import { describe , expect , it , vi } from "vitest" ;
4
4
import { resourceCompletion } from "../resources/completion.js" ;
5
+ import type { Resource } from "../resources/resource.js" ;
5
6
import { resourcesField } from "../state.js" ;
6
- import { Resource } from "../resources/resource.js" ;
7
7
8
8
const createMockResource = ( uri : string , name ?: string ) : Resource => ( {
9
9
uri,
10
+ type : "mock" ,
10
11
name : name || uri ,
11
12
description : `Test resource: ${ uri } ` ,
12
13
mimeType : "text/plain" ,
13
14
data : undefined ,
14
15
} ) ;
15
16
16
- const createMockView = ( doc : string , pos : number ) => {
17
+ const createMockView = ( doc : string , _pos : number ) => {
17
18
const state = EditorState . create ( {
18
19
doc,
19
20
extensions : [ resourcesField ] ,
@@ -27,7 +28,7 @@ const createMockView = (doc: string, pos: number) => {
27
28
28
29
const createMockContext = ( text : string , pos : number , explicit = false ) => {
29
30
const view = createMockView ( text , pos ) ;
30
-
31
+
31
32
return {
32
33
state : view . state ,
33
34
pos,
@@ -37,15 +38,15 @@ const createMockContext = (text: string, pos: number, explicit = false) => {
37
38
const textBefore = text . slice ( 0 , pos ) ;
38
39
const match = textBefore . match ( regex ) ;
39
40
if ( ! match ) return null ;
40
-
41
+
41
42
return {
42
43
from : pos - match [ 0 ] . length ,
43
44
to : pos ,
44
45
text : match [ 0 ] ,
45
46
} ;
46
47
} ,
47
48
aborted : false ,
48
- tokenBefore : ( types : any ) => null ,
49
+ tokenBefore : ( _types : any ) => null ,
49
50
prefix : ( text : string , from : number ) => text . slice ( from , pos ) ,
50
51
} ;
51
52
} ;
@@ -55,32 +56,32 @@ describe("resourceCompletion", () => {
55
56
it ( "should return null when no @ character is present" , async ( ) => {
56
57
const getResources = vi . fn ( ) . mockResolvedValue ( [ ] ) ;
57
58
const completion = resourceCompletion ( getResources ) ;
58
-
59
+
59
60
const context = createMockContext ( "hello world" , 11 ) ;
60
61
const result = await completion ( context ) ;
61
-
62
+
62
63
expect ( result ) . toBeNull ( ) ;
63
64
expect ( getResources ) . not . toHaveBeenCalled ( ) ;
64
65
} ) ;
65
66
66
67
it ( "should return null when @ is at cursor position and not explicit" , async ( ) => {
67
68
const getResources = vi . fn ( ) . mockResolvedValue ( [ ] ) ;
68
69
const completion = resourceCompletion ( getResources ) ;
69
-
70
+
70
71
const context = createMockContext ( "hello @" , 7 , false ) ;
71
72
const result = await completion ( context ) ;
72
-
73
+
73
74
expect ( result ) . toBeNull ( ) ;
74
75
} ) ;
75
76
76
77
it ( "should return completions when @ is at cursor position and explicit" , async ( ) => {
77
78
const resources = [ createMockResource ( "file.txt" ) ] ;
78
79
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
79
80
const completion = resourceCompletion ( getResources ) ;
80
-
81
+
81
82
const context = createMockContext ( "hello @" , 7 , true ) ;
82
83
const result = await completion ( context ) ;
83
-
84
+
84
85
expect ( result ) . not . toBeNull ( ) ;
85
86
expect ( result ?. options ) . toHaveLength ( 1 ) ;
86
87
expect ( result ?. options [ 0 ] . label ) . toBe ( "@file.txt" ) ;
@@ -90,10 +91,10 @@ describe("resourceCompletion", () => {
90
91
const resources = [ createMockResource ( "file.txt" ) ] ;
91
92
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
92
93
const completion = resourceCompletion ( getResources ) ;
93
-
94
+
94
95
const context = createMockContext ( "hello @fi" , 9 ) ;
95
96
const result = await completion ( context ) ;
96
-
97
+
97
98
expect ( result ) . not . toBeNull ( ) ;
98
99
expect ( result ?. options ) . toHaveLength ( 1 ) ;
99
100
expect ( result ?. from ) . toBe ( 6 ) ; // Start of @fi
@@ -102,10 +103,10 @@ describe("resourceCompletion", () => {
102
103
it ( "should return null when no resources are available" , async ( ) => {
103
104
const getResources = vi . fn ( ) . mockResolvedValue ( [ ] ) ;
104
105
const completion = resourceCompletion ( getResources ) ;
105
-
106
+
106
107
const context = createMockContext ( "hello @file" , 11 ) ;
107
108
const result = await completion ( context ) ;
108
-
109
+
109
110
expect ( result ) . toBeNull ( ) ;
110
111
} ) ;
111
112
} ) ;
@@ -118,12 +119,12 @@ describe("resourceCompletion", () => {
118
119
] ;
119
120
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
120
121
const completion = resourceCompletion ( getResources ) ;
121
-
122
+
122
123
const context = createMockContext ( "@" , 1 , true ) ;
123
124
const result = await completion ( context ) ;
124
-
125
+
125
126
expect ( result ?. options ) . toHaveLength ( 2 ) ;
126
-
127
+
127
128
const option1 = result ?. options [ 0 ] ;
128
129
expect ( option1 ?. label ) . toBe ( "@My File" ) ;
129
130
expect ( option1 ?. displayLabel ) . toBe ( "My File" ) ;
@@ -143,10 +144,10 @@ describe("resourceCompletion", () => {
143
144
} ;
144
145
const getResources = vi . fn ( ) . mockResolvedValue ( [ resource ] ) ;
145
146
const completion = resourceCompletion ( getResources ) ;
146
-
147
+
147
148
const context = createMockContext ( "@" , 1 , true ) ;
148
149
const result = await completion ( context ) ;
149
-
150
+
150
151
const option = result ?. options [ 0 ] ;
151
152
expect ( option ?. info ) . toBeUndefined ( ) ;
152
153
expect ( option ?. boost ) . toBe ( 0 ) ;
@@ -162,10 +163,10 @@ describe("resourceCompletion", () => {
162
163
} ;
163
164
const getResources = vi . fn ( ) . mockResolvedValue ( [ resource ] ) ;
164
165
const completion = resourceCompletion ( getResources ) ;
165
-
166
+
166
167
const context = createMockContext ( "@" , 1 , true ) ;
167
168
const result = await completion ( context ) ;
168
-
169
+
169
170
const option = result ?. options [ 0 ] ;
170
171
expect ( option ?. type ) . toBe ( "variable" ) ;
171
172
} ) ;
@@ -179,10 +180,10 @@ describe("resourceCompletion", () => {
179
180
boost : 999 ,
180
181
} ) ;
181
182
const completion = resourceCompletion ( getResources , formatResource ) ;
182
-
183
+
183
184
const context = createMockContext ( "@" , 1 , true ) ;
184
185
const result = await completion ( context ) ;
185
-
186
+
186
187
const option = result ?. options [ 0 ] ;
187
188
expect ( option ?. label ) . toBe ( "Custom Label" ) ;
188
189
expect ( option ?. type ) . toBe ( "custom" ) ;
@@ -196,10 +197,10 @@ describe("resourceCompletion", () => {
196
197
const resources = [ createMockResource ( "file.txt" ) ] ;
197
198
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
198
199
const completion = resourceCompletion ( getResources ) ;
199
-
200
+
200
201
const context = createMockContext ( "@fi" , 3 ) ;
201
202
const result = await completion ( context ) ;
202
-
203
+
203
204
const option = result ?. options [ 0 ] ;
204
205
expect ( option ?. apply ) . toBeDefined ( ) ;
205
206
@@ -210,7 +211,7 @@ describe("resourceCompletion", () => {
210
211
211
212
if ( option ?. apply && typeof option . apply === "function" ) {
212
213
option . apply ( mockView as any , option , 0 , 3 ) ;
213
-
214
+
214
215
expect ( mockView . dispatch ) . toHaveBeenCalledWith ( {
215
216
changes : { from : 0 , to : 3 , insert : "@file.txt " } ,
216
217
} ) ;
@@ -223,17 +224,17 @@ describe("resourceCompletion", () => {
223
224
const resources = [ createMockResource ( "file.txt" ) ] ;
224
225
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
225
226
const completion = resourceCompletion ( getResources ) ;
226
-
227
+
227
228
const view = createMockView ( "@" , 1 ) ;
228
229
const dispatchSpy = vi . spyOn ( view , "dispatch" ) ;
229
-
230
+
230
231
const context = {
231
232
...createMockContext ( "@" , 1 , true ) ,
232
233
view,
233
234
} ;
234
-
235
+
235
236
await completion ( context ) ;
236
-
237
+
237
238
expect ( dispatchSpy ) . toHaveBeenCalledWith ( {
238
239
effects : expect . anything ( ) ,
239
240
} ) ;
@@ -243,14 +244,14 @@ describe("resourceCompletion", () => {
243
244
const resources = [ createMockResource ( "file.txt" ) ] ;
244
245
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
245
246
const completion = resourceCompletion ( getResources ) ;
246
-
247
+
247
248
const context = {
248
249
...createMockContext ( "@" , 1 , true ) ,
249
250
view : undefined ,
250
251
} ;
251
-
252
+
252
253
const result = await completion ( context ) ;
253
-
254
+
254
255
// Should still return completions even without view
255
256
expect ( result ?. options ) . toHaveLength ( 1 ) ;
256
257
} ) ;
@@ -261,10 +262,10 @@ describe("resourceCompletion", () => {
261
262
const resources = [ createMockResource ( "file.txt" ) ] ;
262
263
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
263
264
const completion = resourceCompletion ( getResources ) ;
264
-
265
+
265
266
const context = createMockContext ( "@file" , 5 ) ;
266
267
const result = await completion ( context ) ;
267
-
268
+
268
269
expect ( result ) . not . toBeNull ( ) ;
269
270
expect ( result ?. from ) . toBe ( 0 ) ;
270
271
} ) ;
@@ -273,10 +274,10 @@ describe("resourceCompletion", () => {
273
274
const resources = [ createMockResource ( "file.txt" ) ] ;
274
275
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
275
276
const completion = resourceCompletion ( getResources ) ;
276
-
277
+
277
278
const context = createMockContext ( "hello @file" , 11 ) ;
278
279
const result = await completion ( context ) ;
279
-
280
+
280
281
expect ( result ) . not . toBeNull ( ) ;
281
282
expect ( result ?. from ) . toBe ( 6 ) ;
282
283
} ) ;
@@ -285,20 +286,20 @@ describe("resourceCompletion", () => {
285
286
const resources = [ createMockResource ( "file123.txt" ) ] ;
286
287
const getResources = vi . fn ( ) . mockResolvedValue ( resources ) ;
287
288
const completion = resourceCompletion ( getResources ) ;
288
-
289
+
289
290
const context = createMockContext ( "@file123" , 8 ) ;
290
291
const result = await completion ( context ) ;
291
-
292
+
292
293
expect ( result ) . not . toBeNull ( ) ;
293
294
} ) ;
294
295
295
296
it ( "should not match @ followed by non-word characters" , async ( ) => {
296
297
const getResources = vi . fn ( ) . mockResolvedValue ( [ ] ) ;
297
298
const completion = resourceCompletion ( getResources ) ;
298
-
299
+
299
300
const context = createMockContext ( "@-file" , 6 ) ;
300
301
const result = await completion ( context ) ;
301
-
302
+
302
303
expect ( result ) . toBeNull ( ) ;
303
304
} ) ;
304
305
} ) ;
@@ -307,23 +308,23 @@ describe("resourceCompletion", () => {
307
308
it ( "should handle getResources errors gracefully" , async ( ) => {
308
309
const getResources = vi . fn ( ) . mockRejectedValue ( new Error ( "Failed to fetch" ) ) ;
309
310
const completion = resourceCompletion ( getResources ) ;
310
-
311
+
311
312
const context = createMockContext ( "@file" , 5 ) ;
312
-
313
+
313
314
await expect ( completion ( context ) ) . rejects . toThrow ( "Failed to fetch" ) ;
314
315
} ) ;
315
316
316
317
it ( "should handle malformed resources" , async ( ) => {
317
318
const malformedResource = { uri : "test" } as Resource ;
318
319
const getResources = vi . fn ( ) . mockResolvedValue ( [ malformedResource ] ) ;
319
320
const completion = resourceCompletion ( getResources ) ;
320
-
321
+
321
322
const context = createMockContext ( "@" , 1 , true ) ;
322
323
const result = await completion ( context ) ;
323
-
324
+
324
325
// Should handle gracefully and still create completion
325
326
expect ( result ?. options ) . toHaveLength ( 1 ) ;
326
327
expect ( result ?. options [ 0 ] . label ) . toBe ( "@undefined" ) ; // name is undefined
327
328
} ) ;
328
329
} ) ;
329
- } ) ;
330
+ } ) ;
0 commit comments