From 8808002e54693eb5d23c3897cab0e0f936276d46 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Mon, 8 Feb 2021 10:11:39 -0800 Subject: [PATCH] refactor(language-service): migrate gettcb_spec to new testing package (#40966) refactor(language-service): migrate gettcb_spec to new testing package PR Close #40966 --- .../language-service/ivy/test/gettcb_spec.ts | 60 ++++++++++--------- .../ivy/testing/src/buffer.ts | 4 ++ .../ivy/testing/src/project.ts | 35 +++++++++++ 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/packages/language-service/ivy/test/gettcb_spec.ts b/packages/language-service/ivy/test/gettcb_spec.ts index dec439941c..a753550881 100644 --- a/packages/language-service/ivy/test/gettcb_spec.ts +++ b/packages/language-service/ivy/test/gettcb_spec.ts @@ -6,11 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system'; import {initMockFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing'; -import {extractCursorInfo} from './env'; -import {createModuleWithDeclarations} from './test_utils'; +import {createModuleAndProjectWithDeclarations, LanguageServiceTestEnv} from '../testing'; describe('get typecheck block', () => { beforeEach(() => { @@ -18,20 +16,24 @@ describe('get typecheck block', () => { }); it('should find the typecheck block for an inline template', () => { - const {text, cursor} = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({ - template: '
{{ my¦Prop }}
', + template: '
{{ myProp }}
', }) export class AppCmp { myProp!: string; - }`); - const appFi = absoluteFrom('/app.ts'); - const env = createModuleWithDeclarations([{name: appFi, contents: text}]); + }` + }; + const env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + project.expectNoSourceDiagnostics(); - env.expectNoSourceDiagnostics(); - const result = env.ngLS.getTcb(appFi, cursor); + const appFile = project.openFile('app.ts'); + appFile.moveCursorToText('{{ my¦Prop }}'); + const result = appFile.getTcb(); if (result === undefined) { fail('Expected a valid TCB response'); return; @@ -43,12 +45,8 @@ describe('get typecheck block', () => { }); it('should find the typecheck block for an external template', () => { - const {text, cursor} = extractCursorInfo(`
{{ my¦Prop }}
`); - const templateFi = absoluteFrom('/app.html'); - const env = createModuleWithDeclarations( - [{ - name: absoluteFrom('/app.ts'), - contents: ` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({ @@ -57,11 +55,15 @@ describe('get typecheck block', () => { export class AppCmp { myProp!: string; }`, - }], - [{name: templateFi, contents: text}]); + 'app.html': '
{{ myProp }}
' + }; + const env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + project.expectNoSourceDiagnostics(); - env.expectNoSourceDiagnostics(); - const result = env.ngLS.getTcb(templateFi, cursor); + const htmlFile = project.openFile('app.html'); + htmlFile.moveCursorToText('{{ my¦Prop }}'); + const result = htmlFile.getTcb(); if (result === undefined) { fail('Expected a valid TCB response'); return; @@ -73,20 +75,24 @@ describe('get typecheck block', () => { }); it('should not find typecheck blocks outside a template', () => { - const {text, cursor} = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({ template: '
{{ myProp }}
', }) export class AppCmp { - my¦Prop!: string; - }`); - const appFi = absoluteFrom('/app.ts'); - const env = createModuleWithDeclarations([{name: appFi, contents: text}]); + myProp!: string; + }` + }; + const env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + project.expectNoSourceDiagnostics(); - env.expectNoSourceDiagnostics(); - const result = env.ngLS.getTcb(appFi, cursor); + const appFile = project.openFile('app.ts'); + appFile.moveCursorToText('my¦Prop!: string;'); + const result = appFile.getTcb(); expect(result).toBeUndefined(); }); }); diff --git a/packages/language-service/ivy/testing/src/buffer.ts b/packages/language-service/ivy/testing/src/buffer.ts index 48a90c41cf..1664349891 100644 --- a/packages/language-service/ivy/testing/src/buffer.ts +++ b/packages/language-service/ivy/testing/src/buffer.ts @@ -76,4 +76,8 @@ export class OpenBuffer { return this.ngLS.getCompletionEntryDetails( this.scriptInfo.fileName, this._cursor, entryName, formatOptions, preferences); } + + getTcb() { + return this.ngLS.getTcb(this.scriptInfo.fileName, this._cursor); + } } diff --git a/packages/language-service/ivy/testing/src/project.ts b/packages/language-service/ivy/testing/src/project.ts index e080c280ca..6c5dfccf06 100644 --- a/packages/language-service/ivy/testing/src/project.ts +++ b/packages/language-service/ivy/testing/src/project.ts @@ -8,6 +8,7 @@ import {StrictTemplateOptions} from '@angular/compiler-cli/src/ngtsc/core/api'; import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; +import { OptimizeFor } from '@angular/compiler-cli/src/ngtsc/typecheck/api'; import * as ts from 'typescript/lib/tsserverlibrary'; import {LanguageService} from '../../language_service'; import {OpenBuffer} from './buffer'; @@ -119,4 +120,38 @@ export class Project { diagnostics.push(...this.ngLS.getSemanticDiagnostics(fileName)); return diagnostics; } + + expectNoSourceDiagnostics(): void { + const program = this.tsLS.getProgram(); + if (program === undefined) { + throw new Error(`Expected to get a ts.Program`); + } + + const ngCompiler = this.ngLS.compilerFactory.getOrCreate(); + + for (const sf of program.getSourceFiles()) { + if (sf.isDeclarationFile || sf.fileName.endsWith('.ngtypecheck.ts')) { + continue; + } + + const syntactic = program.getSyntacticDiagnostics(sf); + expect(syntactic.map(diag => diag.messageText)).toEqual([]); + if (syntactic.length > 0) { + continue; + } + + const semantic = program.getSemanticDiagnostics(sf); + expect(semantic.map(diag => diag.messageText)).toEqual([]); + if (semantic.length > 0) { + continue; + } + + // It's more efficient to optimize for WholeProgram since we call this with every file in the + // program. + const ngDiagnostics = ngCompiler.getDiagnosticsForFile(sf, OptimizeFor.WholeProgram); + expect(ngDiagnostics.map(diag => diag.messageText)).toEqual([]); + } + + this.ngLS.compilerFactory.registerLastKnownProgram(); + } }