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 start (#15)', async () => { 113 server.send({ 114 seq: 9, 115 type: 'request', 116 command: 'quickinfo', 117 arguments: { 118 file: testFile, 119 line: 5, 120 offset: 5, 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 139 it('Handles empty line (#190)', async () => { 140 server.send({ 141 seq: 10, 142 type: 'request', 143 command: 'completionInfo', 144 arguments: { 145 file: testFile, 146 line: 14, 147 offset: 3, 148 includeExternalModuleExports: true, 149 includeInsertTextCompletions: true, 150 triggerKind: 1, 151 }, 152 }); 153 154 await server.waitForResponse( 155 response => 156 response.type === 'response' && response.command === 'completionInfo' 157 ); 158 159 const res = server.responses 160 .reverse() 161 .find( 162 resp => resp.type === 'response' && resp.command === 'completionInfo' 163 ); 164 165 expect(res).toBeDefined(); 166 expect(typeof res?.body.entries).toEqual('object'); 167 const defaultAttrs = { kind: 'var', kindModifiers: 'declare' }; 168 expect(res?.body.entries).toEqual([ 169 { 170 ...defaultAttrs, 171 name: 'post', 172 sortText: '0post', 173 labelDetails: { detail: ' Post' }, 174 }, 175 { 176 ...defaultAttrs, 177 name: 'posts', 178 sortText: '1posts', 179 labelDetails: { detail: ' [Post]', description: 'List out all posts' }, 180 }, 181 { 182 ...defaultAttrs, 183 name: '__typename', 184 sortText: '2__typename', 185 labelDetails: { 186 detail: ' String!', 187 description: 'The name of the current Object type at runtime.', 188 }, 189 }, 190 { 191 ...defaultAttrs, 192 name: '__schema', 193 sortText: '3__schema', 194 labelDetails: { 195 detail: ' __Schema!', 196 description: 'Access the current type schema of this server.', 197 }, 198 }, 199 { 200 ...defaultAttrs, 201 name: '__type', 202 sortText: '4__type', 203 labelDetails: { 204 detail: ' __Type', 205 description: 'Request the type information of a single type.', 206 }, 207 }, 208 ]); 209 }, 7500); 210});