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');
11describe('Fragment + operations', () => {
12 const outfileCombinations = path.join(projectPath, 'Combination.ts');
13
14 let server: TSServer;
15 beforeAll(async () => {
16 server = new TSServer(projectPath, { debugLog: false });
17
18 server.sendCommand('open', {
19 file: outfileCombinations,
20 fileContent: '// empty',
21 scriptKindName: 'TS',
22 } satisfies ts.server.protocol.OpenRequestArgs);
23
24 server.sendCommand('updateOpen', {
25 openFiles: [
26 {
27 file: outfileCombinations,
28 fileContent: fs.readFileSync(
29 path.join(projectPath, 'fixtures/Combination.ts'),
30 'utf-8'
31 ),
32 },
33 ],
34 } satisfies ts.server.protocol.UpdateOpenRequestArgs);
35
36 server.sendCommand('saveto', {
37 file: outfileCombinations,
38 tmpfile: outfileCombinations,
39 } satisfies ts.server.protocol.SavetoRequestArgs);
40 });
41
42 afterAll(() => {
43 try {
44 fs.unlinkSync(outfileCombinations);
45 } catch {}
46 });
47
48 it('gives semantic-diagnostics with preceding fragments', async () => {
49 await server.waitForResponse(
50 e => e.type === 'event' && e.event === 'semanticDiag'
51 );
52 const res = server.responses
53 .reverse()
54 .find(resp => resp.type === 'event' && resp.event === 'semanticDiag');
55 expect(res?.body.diagnostics).toMatchInlineSnapshot(`
56 [
57 {
58 "category": "error",
59 "code": 52001,
60 "end": {
61 "line": 7,
62 "offset": 1,
63 },
64 "start": {
65 "line": 6,
66 "offset": 5,
67 },
68 "text": "Cannot query field \\"someUnknownField\\" on type \\"Post\\".",
69 },
70 {
71 "category": "error",
72 "code": 52001,
73 "end": {
74 "line": 11,
75 "offset": 10,
76 },
77 "start": {
78 "line": 11,
79 "offset": 3,
80 },
81 "text": "Cannot query field \\"someUnknownField\\" on type \\"Post\\".",
82 },
83 {
84 "category": "error",
85 "code": 52001,
86 "end": {
87 "line": 17,
88 "offset": 1,
89 },
90 "start": {
91 "line": 16,
92 "offset": 7,
93 },
94 "text": "Cannot query field \\"__typenam\\" on type \\"Post\\".",
95 },
96 ]
97 `);
98 }, 30000);
99
100 it('gives quick-info with preceding fragments', async () => {
101 server.send({
102 seq: 9,
103 type: 'request',
104 command: 'quickinfo',
105 arguments: {
106 file: outfileCombinations,
107 line: 14,
108 offset: 7,
109 },
110 });
111
112 await server.waitForResponse(
113 response =>
114 response.type === 'response' && response.command === 'quickinfo'
115 );
116
117 const res = server.responses
118 .reverse()
119 .find(resp => resp.type === 'response' && resp.command === 'quickinfo');
120
121 expect(res).toBeDefined();
122 expect(typeof res?.body).toEqual('object');
123 expect(res?.body.documentation).toEqual(
124 `Query.posts: [Post]\n\nList out all posts`
125 );
126 }, 30000);
127
128 it('gives suggestions with preceding fragments', async () => {
129 server.send({
130 seq: 10,
131 type: 'request',
132 command: 'completionInfo',
133 arguments: {
134 file: outfileCombinations,
135 line: 15,
136 offset: 7,
137 includeExternalModuleExports: true,
138 includeInsertTextCompletions: true,
139 triggerKind: 1,
140 },
141 });
142
143 await server.waitForResponse(
144 response =>
145 response.type === 'response' && response.command === 'completionInfo'
146 );
147
148 const res = server.responses
149 .reverse()
150 .find(
151 resp => resp.type === 'response' && resp.command === 'completionInfo'
152 );
153
154 expect(res).toBeDefined();
155 expect(typeof res?.body.entries).toEqual('object');
156 expect(res?.body.entries).toMatchInlineSnapshot(`
157 [
158 {
159 "kind": "var",
160 "kindModifiers": "declare",
161 "labelDetails": {
162 "detail": " ID!",
163 },
164 "name": "id",
165 "sortText": "0id",
166 },
167 {
168 "kind": "var",
169 "kindModifiers": "declare",
170 "labelDetails": {
171 "detail": " String!",
172 },
173 "name": "title",
174 "sortText": "1title",
175 },
176 {
177 "kind": "var",
178 "kindModifiers": "declare",
179 "labelDetails": {
180 "detail": " String!",
181 },
182 "name": "content",
183 "sortText": "2content",
184 },
185 {
186 "kind": "var",
187 "kindModifiers": "declare",
188 "labelDetails": {
189 "description": "The name of the current Object type at runtime.",
190 "detail": " String!",
191 },
192 "name": "__typename",
193 "sortText": "3__typename",
194 },
195 ]
196 `);
197 }, 30000);
198});