@@ -14,7 +14,7 @@ const defaultFiles = [
14
14
] as MockFile [ ] ;
15
15
const schemaFile : MockFile = [
16
16
'schema.graphql' ,
17
- 'type Query { foo: Foo }\n\ntype Foo { bar: String }' ,
17
+ 'type Query { foo: Foo }\n\ntype Foo { bar: String }' ,
18
18
] ;
19
19
20
20
const genSchemaPath =
@@ -102,6 +102,22 @@ describe('project with simple config and graphql files', () => {
102
102
] ,
103
103
} ) ;
104
104
await project . init ( 'query.graphql' ) ;
105
+ const initSchemaDefRequest = await project . lsp . handleDefinitionRequest ( {
106
+ textDocument : { uri : project . uri ( 'schema.graphql' ) } ,
107
+ position : { character : 19 , line : 0 } ,
108
+ } ) ;
109
+ expect ( initSchemaDefRequest . length ) . toEqual ( 1 ) ;
110
+ expect ( initSchemaDefRequest [ 0 ] . uri ) . toEqual ( project . uri ( 'schema.graphql' ) ) ;
111
+ expect ( serializeRange ( initSchemaDefRequest [ 0 ] . range ) ) . toEqual ( {
112
+ start : {
113
+ line : 2 ,
114
+ character : 0 ,
115
+ } ,
116
+ end : {
117
+ character : 24 ,
118
+ line : 2 ,
119
+ } ,
120
+ } ) ;
105
121
expect ( project . lsp . _logger . error ) . not . toHaveBeenCalled ( ) ;
106
122
expect ( await project . lsp . _graphQLCache . getSchema ( ) ) . toBeDefined ( ) ;
107
123
// TODO: for some reason the cache result formats the graphql query??
@@ -151,8 +167,26 @@ describe('project with simple config and graphql files', () => {
151
167
} ) ;
152
168
const typeCache =
153
169
project . lsp . _graphQLCache . _typeDefinitionsCache . get ( '/tmp/test-default' ) ;
154
-
155
170
expect ( typeCache ?. get ( 'Test' ) ?. definition . name . value ) . toEqual ( 'Test' ) ;
171
+
172
+ // test in-file schema defs! important!
173
+ const schemaDefRequest = await project . lsp . handleDefinitionRequest ( {
174
+ textDocument : { uri : project . uri ( 'schema.graphql' ) } ,
175
+ position : { character : 19 , line : 0 } ,
176
+ } ) ;
177
+ expect ( schemaDefRequest . length ) . toEqual ( 1 ) ;
178
+ expect ( schemaDefRequest [ 0 ] . uri ) . toEqual ( project . uri ( 'schema.graphql' ) ) ;
179
+ expect ( serializeRange ( schemaDefRequest [ 0 ] . range ) ) . toEqual ( {
180
+ start : {
181
+ line : 7 ,
182
+ character : 0 ,
183
+ } ,
184
+ end : {
185
+ character : 21 ,
186
+ line : 7 ,
187
+ } ,
188
+ } ) ;
189
+
156
190
// TODO: this fragment should now be invalid
157
191
const result = await project . lsp . handleDidOpenOrSaveNotification ( {
158
192
textDocument : { uri : project . uri ( 'fragments.graphql' ) } ,
@@ -237,7 +271,7 @@ describe('project with simple config and graphql files', () => {
237
271
expect ( changeParams ?. diagnostics [ 0 ] . message ) . toEqual (
238
272
'Cannot query field "or" on type "Test".' ,
239
273
) ;
240
- expect ( await project . lsp . _graphQLCache . getSchema ( ) ) . toBeDefined ( ) ;
274
+ expect ( await project . lsp . _graphQLCache . getSchema ( 'default' ) ) . toBeDefined ( ) ;
241
275
242
276
// schema file is present and contains schema
243
277
const file = await readFile ( join ( genSchemaPath ) , { encoding : 'utf-8' } ) ;
@@ -305,10 +339,11 @@ describe('project with simple config and graphql files', () => {
305
339
} ) ;
306
340
// lets remove the fragments file
307
341
await project . deleteFile ( 'fragments.graphql' ) ;
308
- // and add a fragments.ts file
342
+ // and add a fragments.ts file, watched
309
343
await project . addFile (
310
344
'fragments.ts' ,
311
345
'\n\n\nexport const fragment = gql`\n\n fragment T on Test { isTest }\n`' ,
346
+ true ,
312
347
) ;
313
348
314
349
await project . lsp . handleWatchedFilesChangedNotification ( {
@@ -333,4 +368,100 @@ describe('project with simple config and graphql files', () => {
333
368
} ,
334
369
} ) ;
335
370
} ) ;
371
+ it ( 'caches multiple projects with files and schema with a URL config and a local schema' , async ( ) => {
372
+ const project = new MockProject ( {
373
+ files : [
374
+ [
375
+ 'a/fragments.ts' ,
376
+ '\n\n\nexport const fragment = gql`\n\n fragment TestFragment on Test { isTest }\n`' ,
377
+ ] ,
378
+ [
379
+ 'a/query.ts' ,
380
+ '\n\n\nexport const query = gql`query { test() { isTest, ...T } }`' ,
381
+ ] ,
382
+
383
+ [
384
+ 'b/query.ts' ,
385
+ 'import graphql from "graphql"\n\n\nconst a = graphql` query example { test() { isTest ...T } }`' ,
386
+ ] ,
387
+ [
388
+ 'b/fragments.ts' ,
389
+ '\n\n\nexport const fragment = gql`\n\n fragment T on Test { isTest }\n`' ,
390
+ ] ,
391
+ [ 'b/schema.graphql' , schemaFile [ 1 ] ] ,
392
+ [
393
+ 'package.json' ,
394
+ `{ "graphql": { "projects": {
395
+ "a": { "schema": "http://localhost:3100/graphql", "documents": "./a/**" },
396
+ "b": { "schema": "./b/schema.graphql", "documents": "./b/**" } }
397
+ }
398
+ }` ,
399
+ ] ,
400
+ schemaFile ,
401
+ ] ,
402
+ } ) ;
403
+
404
+ const initParams = await project . init ( 'a/query.graphql' ) ;
405
+ expect ( initParams . diagnostics ) . toEqual ( [ ] ) ;
406
+
407
+ expect ( project . lsp . _logger . error ) . not . toHaveBeenCalled ( ) ;
408
+ expect ( await project . lsp . _graphQLCache . getSchema ( 'a' ) ) . toBeDefined ( ) ;
409
+ const file = await readFile ( join ( genSchemaPath . replace ( 'default' , 'a' ) ) , {
410
+ encoding : 'utf-8' ,
411
+ } ) ;
412
+ expect ( file . split ( '\n' ) . length ) . toBeGreaterThan ( 10 ) ;
413
+ // add a new typescript file with empty query to the b project
414
+ // and expect autocomplete to only show options for project b
415
+ await project . addFile (
416
+ 'b/empty.ts' ,
417
+ 'import gql from "graphql-tag"\ngql`query a { }`' ,
418
+ ) ;
419
+ const completion = await project . lsp . handleCompletionRequest ( {
420
+ textDocument : { uri : project . uri ( 'b/empty.ts' ) } ,
421
+ position : { character : 13 , line : 1 } ,
422
+ } ) ;
423
+
424
+ expect ( completion . items ?. length ) . toEqual ( 4 ) ;
425
+ expect ( completion . items . map ( i => i . label ) ) . toEqual ( [
426
+ 'foo' ,
427
+ '__typename' ,
428
+ '__schema' ,
429
+ '__type' ,
430
+ ] ) ;
431
+
432
+ // TODO this didn't work at all, how to register incomplete changes to model autocomplete, etc?
433
+ // project.changeFile(
434
+ // 'b/schema.graphql',
435
+ // schemaFile[1] + '\ntype Example1 { field: }',
436
+ // );
437
+ // await project.lsp.handleWatchedFilesChangedNotification({
438
+ // changes: [
439
+ // { uri: project.uri('b/schema.graphql'), type: FileChangeType.Changed },
440
+ // ],
441
+ // });
442
+ // better - fails on a graphql parsing error! annoying
443
+ // await project.lsp.handleDidChangeNotification({
444
+ // textDocument: { uri: project.uri('b/schema.graphql'), version: 1 },
445
+ // contentChanges: [
446
+ // { text: schemaFile[1] + '\ntype Example1 { field: }' },
447
+ // ],
448
+ // });
449
+
450
+ // const schemaCompletion = await project.lsp.handleCompletionRequest({
451
+ // textDocument: { uri: project.uri('b/schema.graphql') },
452
+ // position: { character: 23, line: 3 },
453
+ // });
454
+ // expect(schemaCompletion.items.map(i => i.label)).toEqual([
455
+ // 'foo',
456
+ // '__typename',
457
+ // '__schema',
458
+ // '__type',
459
+ // ]);
460
+ // this confirms that autocomplete respects cross-project boundaries for types
461
+ const schemaCompletion = await project . lsp . handleCompletionRequest ( {
462
+ textDocument : { uri : project . uri ( 'b/schema.graphql' ) } ,
463
+ position : { character : 21 , line : 0 } ,
464
+ } ) ;
465
+ expect ( schemaCompletion . items . map ( i => i . label ) ) . toEqual ( [ 'Foo' ] ) ;
466
+ } ) ;
336
467
} ) ;
0 commit comments