From 61bfa3d9dfc7c9daecde098aca595b731c3312a0 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Wed, 7 Apr 2021 17:01:04 -0700 Subject: [PATCH] test(language-service): Add test to expose bug caused by source file change (#41500) This commit adds a test to expose the bug caused by source file change in between typecheck programs. PR Close #41500 --- .../ivy/test/compiler_spec.ts | 40 +++++++++++++++++++ .../ivy/testing/src/project.ts | 1 + 2 files changed, 41 insertions(+) diff --git a/packages/language-service/ivy/test/compiler_spec.ts b/packages/language-service/ivy/test/compiler_spec.ts index 33ba654ffb..02dcf23224 100644 --- a/packages/language-service/ivy/test/compiler_spec.ts +++ b/packages/language-service/ivy/test/compiler_spec.ts @@ -173,4 +173,44 @@ describe('language-service/compiler integration', () => { const ngDiagsAfter = project.getDiagnosticsForFile('mod.ts').filter(isNgSpecificDiagnostic); expect(ngDiagsAfter.length).toBe(0); }); + + it('detects source file change in between typecheck programs', () => { + const env = LanguageServiceTestEnv.setup(); + const project = env.addProject('test', { + 'module.ts': ` + import {NgModule} from '@angular/core'; + import {BarCmp} from './bar'; + + @NgModule({ + declarations: [BarCmp], + }) + export class AppModule {} + `, + 'bar.ts': ` + import {Component} from '@angular/core'; + + @Component({ + template: '{{ bar }}', + }) + export class BarCmp { + readonly bar = 'bar'; + } + `, + }); + // The opening of 'bar.ts' causes its version to change, because the internal + // representation switches from TextStorage to ScriptVersionCache. + const bar = project.openFile('bar.ts'); + // When getDiagnostics is called, NgCompiler calls ensureAllShimsForOneFile + // and caches the source file for 'bar.ts' in the input program. + // The input program has not picked up the version change because the project + // is clean (rightly so since there's no user-initiated change). + expect(project.getDiagnosticsForFile('bar.ts').length).toBe(0); + // A new program is generated due to addition of typecheck file. During + // program creation, TS language service does a sweep of all source files, + // and detects the version change. Consequently, it creates a new source + // file for 'bar.ts'. This is a violation of our assumption that a SourceFile + // will never change in between typecheck programs. + bar.moveCursorToText(`template: '{{ b¦ar }}'`); + expect(bar.getQuickInfoAtPosition()).toBeDefined(); + }); }); diff --git a/packages/language-service/ivy/testing/src/project.ts b/packages/language-service/ivy/testing/src/project.ts index a9821c2721..307eadf66d 100644 --- a/packages/language-service/ivy/testing/src/project.ts +++ b/packages/language-service/ivy/testing/src/project.ts @@ -103,6 +103,7 @@ export class Project { // Mark the project as dirty because the act of opening a file may result in the version // changing since TypeScript will `switchToScriptVersionCache` when a file is opened. // Note that this emulates what we have to do in the server/extension as well. + // TODO: remove this once PR #41475 lands this.tsProject.markAsDirty(); scriptInfo = this.tsProject.getScriptInfo(fileName);