Skip to content

Commit 017bf0b

Browse files
kyliaubenlesh
authored andcommitted
test(language-service): Add tests for quickinfo and definition (angular#29990)
`quickinfo` is used for hover tooltip. `definition` is used for "Go to definition". PR Close angular#29990
1 parent f348dea commit 017bf0b

File tree

7 files changed

+127
-40
lines changed

7 files changed

+127
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"seq": 0,
3+
"type": "response",
4+
"command": "definition",
5+
"request_seq": 2,
6+
"success": true,
7+
"body": [
8+
{
9+
"file": "${PWD}/project/app/app.component.ts",
10+
"start": {
11+
"line": 7,
12+
"offset": 30
13+
},
14+
"end": {
15+
"line": 7,
16+
"offset": 47
17+
}
18+
}
19+
]
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"seq": 0,
3+
"type": "response",
4+
"command": "quickinfo",
5+
"request_seq": 2,
6+
"success": true,
7+
"body": {
8+
"kind": "angular",
9+
"kindModifiers": "what does this do?",
10+
"start": {
11+
"line": 5,
12+
"offset": 26
13+
},
14+
"end": {
15+
"line": 5,
16+
"offset": 30
17+
},
18+
"displayString": "property name of AppComponent",
19+
"documentation": "",
20+
"tags": []
21+
}
22+
}

integration/language_service_plugin/matcher.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
import { writeFileSync } from 'fs';
1+
import { writeFileSync, readFileSync } from 'fs';
22

33
const goldens: string[] = process.argv.slice(2);
44

55
export const goldenMatcher: jasmine.CustomMatcherFactories = {
66
toMatchGolden(util: jasmine.MatchersUtil): jasmine.CustomMatcher {
77
return {
88
compare(actual: {command: string}, golden: string): jasmine.CustomMatcherResult {
9-
const expected = require(`./goldens/${golden}`);
10-
const pass = util.equals(actual, expected);
11-
if (!pass && goldens.indexOf(golden) >= 0) {
9+
if (goldens.includes(golden)) {
1210
console.error(`Writing golden file ${golden}`);
1311
writeFileSync(`./goldens/${golden}`, JSON.stringify(actual, null, 2));
1412
return { pass : true };
1513
}
14+
const content = readFileSync(`./goldens/${golden}`, 'utf-8');
15+
const expected = JSON.parse(content.replace("${PWD}", process.env.PWD!));
16+
const pass = util.equals(actual, expected);
1617
return {
1718
pass,
18-
message: `Expected response for '${actual.command}' to match golden file ${golden}.\n` +
19+
message: `Expected ${JSON.stringify(actual, null, 2)} to match golden ` +
20+
`${JSON.stringify(expected, null, 2)}.\n` +
1921
`To generate new golden file, run "yarn golden ${golden}".`,
2022
};
2123
}

integration/language_service_plugin/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"scripts": {
1414
"build": "tsc -p tsconfig.json",
1515
"cleanup": "rm -rf ti-*.log tsserver.log",
16-
"golden": "node generate.js",
16+
"golden": "yarn build && node generate.js",
1717
"test": "yarn cleanup && yarn build && jasmine test.js"
1818
}
1919
}

integration/language_service_plugin/test.ts

+40-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ describe('Angular Language Service', () => {
5050
// https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1055
5151
client.sendRequest('open', {
5252
file: `${PWD}/project/app/app.module.ts`,
53-
fileContent: ""
5453
});
5554
// Server does not send response to geterr request
5655
// https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1770
@@ -77,7 +76,6 @@ describe('Angular Language Service', () => {
7776

7877
client.sendRequest('open', {
7978
file: `${PWD}/project/app/app.component.ts`,
80-
fileContent: "import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n template: `<h1>Hello {{name}}</h1>`,\n})\nexport class AppComponent { name = 'Angular'; }\n"
8179
});
8280

8381
client.sendRequest('geterr', {
@@ -101,4 +99,44 @@ describe('Angular Language Service', () => {
10199
});
102100
expect(response).toMatchGolden('completionInfo.json');
103101
});
102+
103+
it('should perform quickinfo', async () => {
104+
client.sendRequest('open', {
105+
file: `${PWD}/project/app/app.component.ts`,
106+
});
107+
108+
const resp1 = await client.sendRequest('reload', {
109+
file: `${PWD}/project/app/app.component.ts`,
110+
tmpFile: `${PWD}/project/app/app.component.ts`,
111+
}) as any;
112+
expect(resp1.command).toBe('reload');
113+
expect(resp1.success).toBe(true);
114+
115+
const resp2 = await client.sendRequest('quickinfo', {
116+
file: `${PWD}/project/app/app.component.ts`,
117+
line: 5,
118+
offset: 28,
119+
});
120+
expect(resp2).toMatchGolden('quickinfo.json');
121+
});
122+
123+
it('should perform definition', async () => {
124+
client.sendRequest('open', {
125+
file: `${PWD}/project/app/app.component.ts`,
126+
});
127+
128+
const resp1 = await client.sendRequest('reload', {
129+
file: `${PWD}/project/app/app.component.ts`,
130+
tmpFile: `${PWD}/project/app/app.component.ts`,
131+
}) as any;
132+
expect(resp1.command).toBe('reload');
133+
expect(resp1.success).toBe(true);
134+
135+
const resp2 = await client.sendRequest('definition', {
136+
file: `${PWD}/project/app/app.component.ts`,
137+
line: 5,
138+
offset: 28,
139+
});
140+
expect(resp2).toMatchGolden('definition.json');
141+
});
104142
});

integration/language_service_plugin/tsclient.ts

+36-31
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,56 @@ export class Client {
1515
listen() {
1616
this.server.stdout.on('data', (data: Buffer) => {
1717
this.data = this.data ? Buffer.concat([this.data, data]) : data;
18+
// tsserver could batch multiple responses together so we have to go
19+
// through the entire buffer to keep looking for messages.
1820
const CONTENT_LENGTH = 'Content-Length: '
19-
const index = this.data.indexOf(CONTENT_LENGTH);
20-
if (index < 0) {
21-
return;
22-
}
23-
let start = index + CONTENT_LENGTH.length;
24-
let end = this.data.indexOf('\r\n', start);
25-
if (end < start) {
26-
return;
27-
}
28-
const contentLengthStr = this.data.slice(start, end).toString();
29-
const contentLength = Number(contentLengthStr);
30-
if (isNaN(contentLength) || contentLength < 0) {
31-
return;
32-
}
33-
start = end + 4;
34-
end = start + contentLength;
35-
if (end > this.data.length) {
36-
return;
37-
}
38-
const content = this.data.slice(start, end).toString();
39-
this.data = this.data.slice(end);
40-
try {
41-
const payload = JSON.parse(content);
42-
if (payload.type === "event") {
21+
do {
22+
const index = this.data.indexOf(CONTENT_LENGTH);
23+
if (index < 0) {
4324
return;
4425
}
45-
this.responseEmitter.emit('response', payload);
46-
}
47-
catch (error) {
48-
this.responseEmitter.emit('error', error);
49-
}
26+
let start = index + CONTENT_LENGTH.length;
27+
let end = this.data.indexOf('\r\n', start);
28+
if (end < start) {
29+
return;
30+
}
31+
const contentLengthStr = this.data.slice(start, end).toString();
32+
const contentLength = Number(contentLengthStr);
33+
if (isNaN(contentLength) || contentLength < 0) {
34+
return;
35+
}
36+
start = end + 4;
37+
end = start + contentLength;
38+
if (end > this.data.length) {
39+
return;
40+
}
41+
const content = this.data.slice(start, end).toString();
42+
this.data = this.data.slice(end);
43+
try {
44+
const payload = JSON.parse(content);
45+
if (payload.type === "response") {
46+
const seq = `${payload.request_seq}`;
47+
this.responseEmitter.emit(seq, payload);
48+
}
49+
}
50+
catch (error) {
51+
this.responseEmitter.emit('error', error);
52+
}
53+
} while (this.data.length > 0)
5054
});
5155
}
5256

5357
async send(type: string, command: string, params: {}) {
58+
const seq = this.id++;
5459
const request = {
55-
seq: this.id++,
60+
seq,
5661
type,
5762
command,
5863
arguments: params
5964
};
6065
this.server.stdin.write(JSON.stringify(request) + '\r\n');
6166
return new Promise((resolve, reject) => {
62-
this.responseEmitter.once('response', resolve);
67+
this.responseEmitter.once(`${seq}`, resolve);
6368
this.responseEmitter.once('error', reject);
6469
});
6570
}

integration/language_service_plugin/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"compilerOptions": {
33
/* Basic Options */
4-
"target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
4+
"target": "es2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
55
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation. */
77
// "allowJs": true, /* Allow javascript files to be compiled. */

0 commit comments

Comments
 (0)