Skip to content

Commit 3a3146e

Browse files
authored
Add tests for completions crash (microsoft#53472)
1 parent 9bd1a32 commit 3a3146e

File tree

3 files changed

+650
-0
lines changed

3 files changed

+650
-0
lines changed

src/testRunner/unittests/tsserver/exportMapCache.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {
44
File,
55
} from "../virtualFileSystemWithWatch";
66
import {
7+
baselineTsserverLogs,
78
configuredProjectAt,
9+
createLoggerWithInMemoryLogs,
810
createSession,
911
openFilesForSession,
1012
} from "./helpers";
@@ -129,6 +131,94 @@ describe("unittests:: tsserver:: exportMapCache", () => {
129131
assert.ok(sigintPropAfter);
130132
assert.notEqual(symbolIdBefore, ts.getSymbolId(sigintPropAfter![0].symbol));
131133
});
134+
135+
it("invalidates the cache when a file is opened with different contents", () => {
136+
const utilsTs: File = {
137+
path: "/utils.ts",
138+
content: `export class Element {
139+
// ...
140+
}
141+
142+
export abstract class Component {
143+
abstract render(): Element;
144+
}`
145+
};
146+
const classesTs: File = {
147+
path: "/classes.ts",
148+
content: `import { Component } from "./utils.js";
149+
150+
export class MyComponent extends Component {
151+
render/**/
152+
}`
153+
};
154+
const host = createServerHost([utilsTs, classesTs, tsconfig]);
155+
const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
156+
const projectService = session.getProjectService();
157+
openFilesForSession([classesTs], session);
158+
session.executeCommandSeq<ts.server.protocol.ConfigureRequest>({
159+
command: ts.server.protocol.CommandTypes.Configure,
160+
arguments: {
161+
preferences: {
162+
includeCompletionsForModuleExports: true,
163+
includeCompletionsWithClassMemberSnippets: true,
164+
includeCompletionsWithInsertText: true,
165+
},
166+
}
167+
});
168+
session.executeCommandSeq<ts.server.protocol.CompletionsRequest>({
169+
command: ts.server.protocol.CommandTypes.CompletionInfo,
170+
arguments: {
171+
file: classesTs.path,
172+
line: 4,
173+
offset: 23,
174+
prefix: "render",
175+
includeExternalModuleExports: true,
176+
includeInsertTextCompletions: true,
177+
}
178+
});
179+
180+
const project = configuredProjectAt(projectService, 0);
181+
const exportMapCache = project.getCachedExportInfoMap();
182+
assert.ok(exportMapCache.isUsableByFile(classesTs.path as ts.Path));
183+
assert.ok(!exportMapCache.isEmpty());
184+
185+
openFilesForSession([{ file: utilsTs.path, content: utilsTs.content.replace("render", "render2") }], session);
186+
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
187+
command: ts.server.protocol.CommandTypes.UpdateOpen,
188+
arguments: {
189+
changedFiles: [{
190+
fileName: classesTs.path,
191+
textChanges: [{
192+
newText: "",
193+
start: { line: 4, offset: 22 },
194+
end: { line: 4, offset: 23 },
195+
}]
196+
}]
197+
}
198+
});
199+
200+
host.runQueuedTimeoutCallbacks();
201+
project.getPackageJsonAutoImportProvider();
202+
203+
// Cache is invalidated because other file has changed
204+
assert.ok(!exportMapCache.isUsableByFile(classesTs.path as ts.Path));
205+
assert.ok(exportMapCache.isEmpty());
206+
207+
// Does not crash
208+
session.executeCommandSeq<ts.server.protocol.CompletionsRequest>({
209+
command: ts.server.protocol.CommandTypes.CompletionInfo,
210+
arguments: {
211+
file: classesTs.path,
212+
line: 4,
213+
offset: 22,
214+
prefix: "rende",
215+
includeExternalModuleExports: true,
216+
includeInsertTextCompletions: true,
217+
}
218+
});
219+
220+
baselineTsserverLogs("exportMapCache", "invalidates the cache when a file is opened with different contents", session);
221+
});
132222
});
133223

134224
function setup() {

0 commit comments

Comments
 (0)