• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem extra resolution pass in server host", () => {
3        it("can load typings that are proper modules", () => {
4            const file1 = {
5                path: "/a/b/app.js",
6                content: `var x = require("lib")`
7            };
8            const lib = {
9                path: "/a/cache/node_modules/@types/lib/index.d.ts",
10                content: "export let x = 1"
11            };
12            const host: TestServerHost & ModuleResolutionHost = createServerHost([file1, lib]);
13            const projectService = createProjectService(host, {
14                typingsInstaller: new TestTypingsInstaller("/a/cache", /*throttleLimit*/5, host),
15                logger: createLoggerWithInMemoryLogs(host)
16            });
17
18            projectService.setCompilerOptionsForInferredProjects({ traceResolution: true, allowJs: true });
19            projectService.openClientFile(file1.path);
20            baselineTsserverLogs("resolutionCache", "can load typings that are proper modules", projectService);
21        });
22    });
23
24    describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem watching @types", () => {
25        it("works correctly when typings are added or removed", () => {
26            const f1 = {
27                path: "/a/b/app.ts",
28                content: "let x = 1;"
29            };
30            const t1 = {
31                path: "/a/b/node_modules/@types/lib1/index.d.ts",
32                content: "export let a: number"
33            };
34            const t2 = {
35                path: "/a/b/node_modules/@types/lib2/index.d.ts",
36                content: "export let b: number"
37            };
38            const tsconfig = {
39                path: "/a/b/tsconfig.json",
40                content: JSON.stringify({
41                    compilerOptions: {},
42                    exclude: ["node_modules"]
43                })
44            };
45            const host = createServerHost([f1, t1, tsconfig]);
46            const projectService = createProjectService(host);
47
48            projectService.openClientFile(f1.path);
49            projectService.checkNumberOfProjects({ configuredProjects: 1 });
50            checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, t1.path, tsconfig.path]);
51
52            // delete t1
53            host.deleteFile(t1.path);
54            // run throttled operation
55            host.runQueuedTimeoutCallbacks();
56
57            projectService.checkNumberOfProjects({ configuredProjects: 1 });
58            checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
59
60            // create t2
61            host.writeFile(t2.path, t2.content);
62            // run throttled operation
63            host.runQueuedTimeoutCallbacks();
64
65            projectService.checkNumberOfProjects({ configuredProjects: 1 });
66            checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, t2.path, tsconfig.path]);
67        });
68    });
69
70    describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem add the missing module file for inferred project", () => {
71        it("should remove the `module not found` error", () => {
72            const moduleFile = {
73                path: "/a/b/moduleFile.ts",
74                content: "export function bar() { };"
75            };
76            const file1 = {
77                path: "/a/b/file1.ts",
78                content: "import * as T from './moduleFile'; T.bar();"
79            };
80            const host = createServerHost([file1]);
81            const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
82            openFilesForSession([file1], session);
83            const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
84                server.CommandNames.SemanticDiagnosticsSync,
85                { file: file1.path }
86            );
87            session.executeCommand(getErrRequest);
88
89            host.writeFile(moduleFile.path, moduleFile.content);
90            host.runQueuedTimeoutCallbacks();
91
92            // Make a change to trigger the program rebuild
93            const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>(
94                server.CommandNames.Change,
95                { file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" }
96            );
97            session.executeCommand(changeRequest);
98
99            // Recheck
100            session.executeCommand(getErrRequest);
101            baselineTsserverLogs("resolutionCache", "should remove the module not found error", session);
102        });
103
104        it("npm install @types works", () => {
105            const folderPath = "/a/b/projects/temp";
106            const file1: File = {
107                path: `${folderPath}/a.ts`,
108                content: 'import f = require("pad"); f;'
109            };
110            const host = createServerHost([file1, libFile]);
111            const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
112            session.executeCommandSeq<protocol.OpenRequest>({
113                command: server.CommandNames.Open,
114                arguments: {
115                    file: file1.path,
116                    fileContent: file1.content,
117                    scriptKindName: "TS",
118                    projectRootPath: folderPath
119                }
120            });
121
122            verifyGetErrRequest({ session, host, files: [file1] });
123
124            const padIndex: File = {
125                path: `${folderPath}/node_modules/@types/pad/index.d.ts`,
126                content: "export = pad;declare function pad(length: number, text: string, char ?: string): string;"
127            };
128            host.ensureFileOrFolder(padIndex, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true);
129            host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
130            host.runQueuedTimeoutCallbacks(); // Actual update
131            host.runQueuedTimeoutCallbacks();
132            host.runQueuedImmediateCallbacks();
133            baselineTsserverLogs("resolutionCache", `npm install @types works`, session);
134        });
135
136        it("suggestion diagnostics", () => {
137            const file: File = {
138                path: "/a.js",
139                content: "function f(p) {}",
140            };
141
142            const host = createServerHost([file]);
143            const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
144
145            session.executeCommandSeq<protocol.OpenRequest>({
146                command: server.CommandNames.Open,
147                arguments: { file: file.path, fileContent: file.content },
148            });
149
150            host.checkTimeoutQueueLength(0);
151            verifyGetErrRequest({ session, host, files: [file] });
152            baselineTsserverLogs("resolutionCache", `suggestion diagnostics`, session);
153        });
154
155        it("disable suggestion diagnostics", () => {
156            const file: File = {
157                path: "/a.js",
158                content: 'require("b")',
159            };
160
161            const host = createServerHost([file]);
162            const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
163
164            session.executeCommandSeq<protocol.OpenRequest>({
165                command: server.CommandNames.Open,
166                arguments: { file: file.path, fileContent: file.content },
167            });
168
169            session.executeCommandSeq<protocol.ConfigureRequest>({
170                command: server.CommandNames.Configure,
171                arguments: {
172                    preferences: { disableSuggestions: true }
173                },
174            });
175
176            host.checkTimeoutQueueLength(0);
177            verifyGetErrRequest({ session, host, files: [file], skip: [{ suggestion: true }] });
178            baselineTsserverLogs("resolutionCache", `disable suggestion diagnostics`, session);
179        });
180
181        it("suppressed diagnostic events", () => {
182            const file: File = {
183                path: "/a.ts",
184                content: "1 = 2;",
185            };
186
187            const host = createServerHost([file]);
188            const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) });
189
190            session.executeCommandSeq<protocol.OpenRequest>({
191                command: server.CommandNames.Open,
192                arguments: { file: file.path, fileContent: file.content },
193            });
194
195            host.checkTimeoutQueueLength(0);
196            session.executeCommandSeq<protocol.GeterrRequest>({
197                command: server.CommandNames.Geterr,
198                arguments: {
199                    delay: 0,
200                    files: [file.path],
201                }
202            });
203
204            host.checkTimeoutQueueLength(0);
205            session.executeCommandSeq<protocol.GeterrForProjectRequest>({
206                command: server.CommandNames.Geterr,
207                arguments: {
208                    delay: 0,
209                    file: file.path,
210                }
211            });
212
213            host.checkTimeoutQueueLength(0);
214            baselineTsserverLogs("resolutionCache", "suppressed diagnostic events", session);
215        });
216    });
217
218    describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem rename a module file and rename back", () => {
219        it("should restore the states for inferred projects", () => {
220            const moduleFile = {
221                path: "/a/b/moduleFile.ts",
222                content: "export function bar() { };"
223            };
224            const file1 = {
225                path: "/a/b/file1.ts",
226                content: "import * as T from './moduleFile'; T.bar();"
227            };
228            const host = createServerHost([moduleFile, file1]);
229            const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
230
231            openFilesForSession([file1], session);
232            const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
233                server.CommandNames.SemanticDiagnosticsSync,
234                { file: file1.path }
235            );
236            session.executeCommand(getErrRequest);
237
238            const moduleFileNewPath = "/a/b/moduleFile1.ts";
239            host.renameFile(moduleFile.path, moduleFileNewPath);
240            host.runQueuedTimeoutCallbacks();
241            session.executeCommand(getErrRequest);
242
243            host.renameFile(moduleFileNewPath, moduleFile.path);
244            host.runQueuedTimeoutCallbacks();
245
246            // Make a change to trigger the program rebuild
247            const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>(
248                server.CommandNames.Change,
249                { file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" }
250            );
251            session.executeCommand(changeRequest);
252            host.runQueuedTimeoutCallbacks();
253
254            session.executeCommand(getErrRequest);
255            baselineTsserverLogs("resolutionCache", "renaming module should restore the states for inferred projects", session);
256        });
257
258        it("should restore the states for configured projects", () => {
259            const moduleFile = {
260                path: "/a/b/moduleFile.ts",
261                content: "export function bar() { };"
262            };
263            const file1 = {
264                path: "/a/b/file1.ts",
265                content: "import * as T from './moduleFile'; T.bar();"
266            };
267            const configFile = {
268                path: "/a/b/tsconfig.json",
269                content: `{}`
270            };
271            const host = createServerHost([moduleFile, file1, configFile]);
272            const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
273
274            openFilesForSession([file1], session);
275            const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
276                server.CommandNames.SemanticDiagnosticsSync,
277                { file: file1.path }
278            );
279            session.executeCommand(getErrRequest);
280
281            const moduleFileNewPath = "/a/b/moduleFile1.ts";
282            host.renameFile(moduleFile.path, moduleFileNewPath);
283            host.runQueuedTimeoutCallbacks();
284            session.executeCommand(getErrRequest);
285
286            host.renameFile(moduleFileNewPath, moduleFile.path);
287            host.runQueuedTimeoutCallbacks();
288            session.executeCommand(getErrRequest);
289            baselineTsserverLogs("resolutionCache", "renaming module should restore the states for configured projects", session);
290        });
291
292        it("should property handle missing config files", () => {
293            const f1 = {
294                path: "/a/b/app.ts",
295                content: "let x = 1"
296            };
297            const config = {
298                path: "/a/b/tsconfig.json",
299                content: "{}"
300            };
301            const projectName = "project1";
302            const host = createServerHost([f1]);
303            const projectService = createProjectService(host);
304            projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName });
305
306            // should have one external project since config file is missing
307            projectService.checkNumberOfProjects({ externalProjects: 1 });
308
309            host.writeFile(config.path, config.content);
310            projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName });
311            projectService.checkNumberOfProjects({ configuredProjects: 1 });
312        });
313
314        it("types should load from config file path if config exists", () => {
315            const f1 = {
316                path: "/a/b/app.ts",
317                content: "let x = 1"
318            };
319            const config = {
320                path: "/a/b/tsconfig.json",
321                content: JSON.stringify({ compilerOptions: { types: ["node"], typeRoots: [] } })
322            };
323            const node = {
324                path: "/a/b/node_modules/@types/node/index.d.ts",
325                content: "declare var process: any"
326            };
327            const cwd = {
328                path: "/a/c"
329            };
330            const host = createServerHost([f1, config, node, cwd], { currentDirectory: cwd.path });
331            const projectService = createProjectService(host);
332            projectService.openClientFile(f1.path);
333            projectService.checkNumberOfProjects({ configuredProjects: 1 });
334            checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, node.path, config.path]);
335        });
336    });
337
338    describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem module resolution caching", () => {
339        const configFile: File = {
340            path: `${tscWatch.projectRoot}/tsconfig.json`,
341            content: JSON.stringify({ compilerOptions: { traceResolution: true } })
342        };
343
344        function getModules(module1Path: string, module2Path: string) {
345            const module1: File = {
346                path: module1Path,
347                content: `export function module1() {}`
348            };
349            const module2: File = {
350                path: module2Path,
351                content: `export function module2() {}`
352            };
353            return { module1, module2 };
354        }
355
356        describe("from files in same folder", () => {
357            function getFiles(fileContent: string) {
358                const file1: File = {
359                    path: `${tscWatch.projectRoot}/src/file1.ts`,
360                    content: fileContent
361                };
362                const file2: File = {
363                    path: `${tscWatch.projectRoot}/src/file2.ts`,
364                    content: fileContent
365                };
366                return { file1, file2 };
367            }
368
369            it("relative module name", () => {
370                const fileContent = `import { module1 } from "./module1";import { module2 } from "../module2";`;
371                const { file1, file2 } = getFiles(fileContent);
372                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/module1.ts`, `${tscWatch.projectRoot}/module2.ts`);
373                const files = [module1, module2, file1, file2, configFile, libFile];
374                const host = createServerHost(files);
375                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
376                service.openClientFile(file1.path);
377
378                host.writeFile(file1.path, file1.content + fileContent);
379                host.writeFile(file2.path, file2.content + fileContent);
380                host.runQueuedTimeoutCallbacks();
381
382                baselineTsserverLogs("resolutionCache", "relative module name from files in same folder", service);
383            });
384
385            it("non relative module name", () => {
386                const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`;
387                const { file1, file2 } = getFiles(fileContent);
388                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`);
389                const files = [module1, module2, file1, file2, configFile, libFile];
390                const host = createServerHost(files);
391                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
392                service.openClientFile(file1.path);
393
394                host.writeFile(file1.path, file1.content + fileContent);
395                host.writeFile(file2.path, file2.content + fileContent);
396                host.runQueuedTimeoutCallbacks();
397                baselineTsserverLogs("resolutionCache", "non relative module name from files in same folder", service);
398            });
399        });
400
401        describe("from files in different folders", () => {
402            function getFiles(fileContent1: string, fileContent2 = fileContent1, fileContent3 = fileContent1, fileContent4 = fileContent1) {
403                const file1: File = {
404                    path: `${tscWatch.projectRoot}/product/src/file1.ts`,
405                    content: fileContent1
406                };
407                const file2: File = {
408                    path: `${tscWatch.projectRoot}/product/src/feature/file2.ts`,
409                    content: fileContent2
410                };
411                const file3: File = {
412                    path: `${tscWatch.projectRoot}/product/test/src/file3.ts`,
413                    content: fileContent3
414                };
415                const file4: File = {
416                    path: `${tscWatch.projectRoot}/product/test/file4.ts`,
417                    content: fileContent4
418                };
419                return { file1, file2, file3, file4 };
420            }
421
422            it("relative module name", () => {
423                const fileContent1 = `import { module1 } from "./module1";import { module2 } from "../module2";`;
424                const fileContent2 = `import { module1 } from "../module1";import { module2 } from "../../module2";`;
425                const fileContent3 = `import { module1 } from "../../src/module1";import { module2 } from "../../module2";`;
426                const fileContent4 = `import { module1 } from "../src/module1}";import { module2 } from "../module2";`;
427                const { file1, file2, file3, file4 } = getFiles(fileContent1, fileContent2, fileContent3, fileContent4);
428                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/src/module1.ts`, `${tscWatch.projectRoot}/product/module2.ts`);
429                const files = [module1, module2, file1, file2, file3, file4, configFile, libFile];
430                const host = createServerHost(files);
431                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
432                service.openClientFile(file1.path);
433
434                host.writeFile(file1.path, file1.content + fileContent1);
435                host.writeFile(file2.path, file2.content + fileContent2);
436                host.writeFile(file3.path, file3.content + fileContent3);
437                host.writeFile(file4.path, file4.content + fileContent4);
438                host.runQueuedTimeoutCallbacks();
439                baselineTsserverLogs("resolutionCache", "relative module name from files in different folders", service);
440            });
441
442            it("non relative module name", () => {
443                const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`;
444                const { file1, file2, file3, file4 } = getFiles(fileContent);
445                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`);
446                const files = [module1, module2, file1, file2, file3, file4, configFile, libFile];
447                const host = createServerHost(files);
448                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
449                service.openClientFile(file1.path);
450
451                host.writeFile(file1.path, file1.content + fileContent);
452                host.writeFile(file2.path, file2.content + fileContent);
453                host.writeFile(file3.path, file3.content + fileContent);
454                host.writeFile(file4.path, file4.content + fileContent);
455                host.runQueuedTimeoutCallbacks();
456                baselineTsserverLogs("resolutionCache", "non relative module name from files in different folders", service);
457            });
458
459            it("non relative module name from inferred project", () => {
460                const module1Name = "module1";
461                const module2Name = "module2";
462                const file2Name = "./feature/file2";
463                const file3Name = "../test/src/file3";
464                const file4Name = "../test/file4";
465                const importModuleContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`;
466                const { file1, file2, file3, file4 } = getFiles(`import "${file2Name}"; import "${file4Name}"; import "${file3Name}"; ${importModuleContent}`, importModuleContent, importModuleContent, importModuleContent);
467                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`);
468                const files = [module1, module2, file1, file2, file3, file4, libFile];
469                const host = createServerHost(files);
470                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
471                service.setCompilerOptionsForInferredProjects({ traceResolution: true });
472                service.openClientFile(file1.path);
473                host.writeFile(file1.path, file1.content + importModuleContent);
474                host.writeFile(file2.path, file2.content + importModuleContent);
475                host.writeFile(file3.path, file3.content + importModuleContent);
476                host.writeFile(file4.path, file4.content + importModuleContent);
477                host.runQueuedTimeoutCallbacks();
478                baselineTsserverLogs("resolutionCache", "non relative module name from inferred project", service);
479            });
480        });
481
482        describe("when watching directories for failed lookup locations in amd resolution", () => {
483            function verifyModuleResolution(scenario: string, useNodeFile: boolean) {
484                it(scenario, () => {
485                    const nodeFile: File = {
486                        path: `${tscWatch.projectRoot}/src/typings/node.d.ts`,
487                        content: `
488declare module "fs" {
489    export interface something {
490    }
491}`
492                    };
493                    const electronFile: File = {
494                        path: `${tscWatch.projectRoot}/src/typings/electron.d.ts`,
495                        content: `
496declare module 'original-fs' {
497    import * as fs from 'fs';
498    export = fs;
499}`
500                    };
501                    const srcFile: File = {
502                        path: `${tscWatch.projectRoot}/src/somefolder/srcfile.ts`,
503                        content: `
504import { x } from "somefolder/module1";
505import { x } from "somefolder/module2";
506const y = x;`
507                    };
508                    const moduleFile: File = {
509                        path: `${tscWatch.projectRoot}/src/somefolder/module1.ts`,
510                        content: `
511export const x = 10;`
512                    };
513                    const configFile: File = {
514                        path: `${tscWatch.projectRoot}/src/tsconfig.json`,
515                        content: JSON.stringify({
516                            compilerOptions: {
517                                module: "amd",
518                                moduleResolution: "classic",
519                                target: "es5",
520                                outDir: "../out",
521                                baseUrl: "./",
522                                typeRoots: ["typings"]
523                            }
524                        })
525                    };
526
527                    const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile];
528                    const host = createServerHost(files);
529                    const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
530                    service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, tscWatch.projectRoot);
531                    baselineTsserverLogs("resolutionCache", scenario, service);
532                });
533            }
534            verifyModuleResolution("when resolves to ambient module", /*useNodeFile*/ true);
535            verifyModuleResolution("when resolution fails", /*useNodeFile*/ false);
536        });
537
538        describe("ignores files/folder changes in node_modules that start with '.'", () => {
539            const npmCacheFile: File = {
540                path: `${tscWatch.projectRoot}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`,
541                content: JSON.stringify({ something: 10 })
542            };
543            const file1: File = {
544                path: `${tscWatch.projectRoot}/test.ts`,
545                content: `import { x } from "somemodule";`
546            };
547            const file2: File = {
548                path: `${tscWatch.projectRoot}/node_modules/somemodule/index.d.ts`,
549                content: `export const x = 10;`
550            };
551            it("when watching node_modules in inferred project for failed lookup/closed script infos", () => {
552                const files = [libFile, file1, file2];
553                const host = createServerHost(files);
554                const service = createProjectService(host);
555                service.openClientFile(file1.path);
556                checkNumberOfProjects(service, { inferredProjects: 1 });
557                const project = service.inferredProjects[0];
558                checkProjectActualFiles(project, files.map(f => f.path));
559                host.checkTimeoutQueueLength(0);
560
561                host.ensureFileOrFolder(npmCacheFile);
562                host.checkTimeoutQueueLength(0);
563            });
564            it("when watching node_modules as part of wild card directories in config project", () => {
565                const config: File = {
566                    path: `${tscWatch.projectRoot}/tsconfig.json`,
567                    content: "{}"
568                };
569                const files = [libFile, file1, file2, config];
570                const host = createServerHost(files);
571                const service = createProjectService(host);
572                service.openClientFile(file1.path);
573                checkNumberOfProjects(service, { configuredProjects: 1 });
574                const project = Debug.checkDefined(service.configuredProjects.get(config.path));
575                checkProjectActualFiles(project, files.map(f => f.path));
576                host.checkTimeoutQueueLength(0);
577
578                host.ensureFileOrFolder(npmCacheFile);
579                host.checkTimeoutQueueLength(0);
580            });
581        });
582
583        describe("avoid unnecessary invalidation", () => {
584            it("unnecessary lookup invalidation on save", () => {
585                const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`;
586                const file1: File = {
587                    path: `${tscWatch.projectRoot}/src/file1.ts`,
588                    content: fileContent
589                };
590                const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`);
591                const files = [module1, module2, file1, configFile, libFile];
592                const host = createServerHost(files);
593                const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
594                service.openClientFile(file1.path);
595
596                // invoke callback to simulate saving
597                host.modifyFile(file1.path, file1.content, { invokeFileDeleteCreateAsPartInsteadOfChange: true });
598                host.checkTimeoutQueueLengthAndRun(0);
599                baselineTsserverLogs("resolutionCache", "avoid unnecessary lookup invalidation on save", service);
600            });
601        });
602    });
603}
604