angular-cn/packages/language-service/ivy/test/diagnostic_spec.ts

249 lines
7.6 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {initMockFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
import * as ts from 'typescript';
import {createModuleAndProjectWithDeclarations, LanguageServiceTestEnv} from '../testing';
describe('getSemanticDiagnostics', () => {
let env: LanguageServiceTestEnv;
beforeEach(() => {
initMockFileSystem('Native');
env = LanguageServiceTestEnv.setup();
});
it('should not produce error for a minimal component definition', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
template: ''
})
export class AppComponent {}
`
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.ts');
expect(diags.length).toEqual(0);
});
it('should report member does not exist', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
template: '{{nope}}'
})
export class AppComponent {}
`
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.ts');
expect(diags.length).toBe(1);
const {category, file, messageText} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(file?.fileName).toBe('/test/app.ts');
expect(messageText).toBe(`Property 'nope' does not exist on type 'AppComponent'.`);
});
it('should process external template', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
templateUrl: './app.html'
})
export class AppComponent {}
`,
'app.html': `Hello world!`
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.html');
expect(diags).toEqual([]);
});
it('should not report external template diagnostics on the TS file', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
templateUrl: './app.html'
})
export class AppComponent {}
`,
'app.html': '{{nope}}'
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.ts');
expect(diags).toEqual([]);
});
it('should report diagnostics in inline templates', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
template: '{{nope}}',
})
export class AppComponent {}
`
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.ts');
expect(diags.length).toBe(1);
const {category, file, messageText} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(file?.fileName).toBe('/test/app.ts');
expect(messageText).toBe(`Property 'nope' does not exist on type 'AppComponent'.`);
});
it('should report member does not exist in external template', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
templateUrl: './app.html'
})
export class AppComponent {}
`,
'app.html': '{{nope}}'
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.html');
expect(diags.length).toBe(1);
const {category, file, messageText} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(file?.fileName).toBe('/test/app.html');
expect(messageText).toBe(`Property 'nope' does not exist on type 'AppComponent'.`);
});
it('should report a parse error in external template', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
templateUrl: './app.html'
})
export class AppComponent {
nope = false;
}
`,
'app.html': '{{nope = true}}'
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.html');
expect(diags.length).toBe(1);
const {category, file, messageText} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(file?.fileName).toBe('/test/app.html');
expect(messageText)
.toContain(
`Parser Error: Bindings cannot contain assignments at column 8 in [{{nope = true}}]`);
});
it('reports html parse errors along with typecheck errors as diagnostics', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
templateUrl: './app.html'
})
export class AppComponent {
nope = false;
}
`,
'app.html': '<dne'
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.html');
expect(diags.length).toBe(2);
expect(diags[0].category).toBe(ts.DiagnosticCategory.Error);
expect(diags[0].file?.fileName).toBe('/test/app.html');
expect(diags[0].messageText).toContain(`'dne' is not a known element`);
expect(diags[1].category).toBe(ts.DiagnosticCategory.Error);
expect(diags[1].file?.fileName).toBe('/test/app.html');
expect(diags[1].messageText).toContain(`Opening tag "dne" not terminated.`);
});
it('should report parse errors of components defined in the same ts file', () => {
const files = {
'app.ts': `
import {Component, NgModule} from '@angular/core';
@Component({ templateUrl: './app1.html' })
export class AppComponent1 { nope = false; }
@Component({ templateUrl: './app2.html' })
export class AppComponent2 { nope = false; }
`,
'app1.html': '{{nope = false}}',
'app2.html': '{{nope = true}}',
'app-module.ts': `
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AppComponent, AppComponent2} from './app';
@NgModule({
declarations: [AppComponent, AppComponent2],
imports: [CommonModule],
})
export class AppModule {}
`
};
const project = env.addProject('test', files);
const diags1 = project.getDiagnosticsForFile('app1.html');
expect(diags1.length).toBe(1);
expect(diags1[0].messageText)
.toBe(
'Parser Error: Bindings cannot contain assignments at column 8 in [{{nope = false}}] in /test/app1.html@0:0');
const diags2 = project.getDiagnosticsForFile('app2.html');
expect(diags2.length).toBe(1);
expect(diags2[0].messageText)
.toBe(
'Parser Error: Bindings cannot contain assignments at column 8 in [{{nope = true}}] in /test/app2.html@0:0');
});
it('reports a diagnostic for a component without a template', () => {
const files = {
'app.ts': `
import {Component} from '@angular/core';
@Component({})
export class MyComponent {}
`
};
const project = createModuleAndProjectWithDeclarations(env, 'test', files);
const diags = project.getDiagnosticsForFile('app.ts');
expect(diags.map(x => x.messageText)).toEqual([
'component is missing a template',
]);
});
});