Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.
1import { expect, afterAll, beforeAll, it, describe } from 'vitest'; 2import { TSServer } from './server'; 3import path from 'node:path'; 4import fs from 'node:fs'; 5import url from 'node:url'; 6import ts from 'typescript/lib/tsserverlibrary'; 7 8const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 9 10const projectPath = path.resolve(__dirname, 'fixture-project'); 11 12let server: TSServer; 13 14describe('simple', () => { 15 const testFile = path.join(projectPath, 'simple.ts'); 16 const generatedFile = path.join(projectPath, 'simple.generated.ts'); 17 const baseGeneratedFile = path.join( 18 projectPath, 19 '__generated__/baseGraphQLSP.ts' 20 ); 21 22 beforeAll(async () => { 23 server = new TSServer(projectPath, { debugLog: false }); 24 const fixtureFileContent = fs.readFileSync( 25 path.resolve(testFile, '../fixtures/simple.ts'), 26 'utf-8' 27 ); 28 29 server.sendCommand('open', { 30 file: testFile, 31 fileContent: '// empty', 32 scriptKindName: 'TS', 33 } satisfies ts.server.protocol.OpenRequestArgs); 34 35 server.sendCommand('updateOpen', { 36 openFiles: [{ file: testFile, fileContent: fixtureFileContent }], 37 } satisfies ts.server.protocol.UpdateOpenRequestArgs); 38 39 server.sendCommand('saveto', { 40 file: testFile, 41 tmpfile: testFile, 42 } satisfies ts.server.protocol.SavetoRequestArgs); 43 44 await server.waitForResponse( 45 response => response.type === 'event' && response.event === 'setTypings' 46 ); 47 }); 48 49 afterAll(() => { 50 try { 51 fs.unlinkSync(testFile); 52 fs.unlinkSync(generatedFile); 53 fs.unlinkSync(baseGeneratedFile); 54 } catch {} 55 server.close(); 56 }); 57 58 it('Proposes suggestions for a selection-set', async () => { 59 server.send({ 60 seq: 8, 61 type: 'request', 62 command: 'completionInfo', 63 arguments: { 64 file: testFile, 65 line: 7, 66 offset: 7, 67 includeExternalModuleExports: true, 68 includeInsertTextCompletions: true, 69 triggerKind: 1, 70 }, 71 }); 72 73 await server.waitForResponse( 74 response => 75 response.type === 'response' && response.command === 'completionInfo' 76 ); 77 78 const res = server.responses 79 .reverse() 80 .find( 81 resp => resp.type === 'response' && resp.command === 'completionInfo' 82 ); 83 84 expect(res).toBeDefined(); 85 expect(typeof res?.body.entries).toEqual('object'); 86 const defaultAttrs = { kind: 'var', kindModifiers: 'declare' }; 87 expect(res?.body.entries).toEqual([ 88 { 89 ...defaultAttrs, 90 name: 'id', 91 sortText: '0id', 92 labelDetails: { detail: ' ID!' }, 93 }, 94 { 95 ...defaultAttrs, 96 name: 'content', 97 sortText: '2content', 98 labelDetails: { detail: ' String!' }, 99 }, 100 { 101 ...defaultAttrs, 102 name: '__typename', 103 sortText: '3__typename', 104 labelDetails: { 105 detail: ' String!', 106 description: 'The name of the current Object type at runtime.', 107 }, 108 }, 109 ]); 110 }, 7500); 111 112 it('Gives quick-info when hovering', async () => { 113 server.send({ 114 seq: 9, 115 type: 'request', 116 command: 'quickinfo', 117 arguments: { 118 file: testFile, 119 line: 5, 120 offset: 7, 121 }, 122 }); 123 124 await server.waitForResponse( 125 response => 126 response.type === 'response' && response.command === 'quickinfo' 127 ); 128 129 const res = server.responses 130 .reverse() 131 .find(resp => resp.type === 'response' && resp.command === 'quickinfo'); 132 expect(res).toBeDefined(); 133 expect(typeof res?.body).toEqual('object'); 134 expect(res?.body.documentation).toEqual( 135 `Query.posts: [Post]\n\nList out all posts` 136 ); 137 }, 7500); 138});