/** * @license * Copyright Google Inc. 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 * as ts from 'typescript'; import {createLanguageService} from '../src/language_service'; import {Diagnostics} from '../src/types'; import {TypeScriptServiceHost} from '../src/typescript_host'; import {toh} from './test_data'; import {MockTypescriptHost, includeDiagnostic, noDiagnostics} from './test_utils'; describe('diagnostics', () => { let documentRegistry = ts.createDocumentRegistry(); let mockHost = new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], toh); let service = ts.createLanguageService(mockHost, documentRegistry); let ngHost = new TypeScriptServiceHost(mockHost, service); let ngService = createLanguageService(ngHost); ngHost.setSite(ngService); it('should be no diagnostics for test.ng', () => { expect(ngService.getDiagnostics('/app/test.ng')).toEqual([]); }); describe('for semantic errors', () => { const fileName = '/app/test.ng'; function diagnostics(template: string): Diagnostics { try { mockHost.override(fileName, template); return ngService.getDiagnostics(fileName); } finally { mockHost.override(fileName, undefined); } } function accept(template: string) { noDiagnostics(diagnostics(template)); } function reject(template: string, message: string): void; function reject(template: string, message: string, at: string): void; function reject(template: string, message: string, location: string): void; function reject(template: string, message: string, location: string, len: number): void; function reject(template: string, message: string, at?: number | string, len?: number): void { if (typeof at == 'string') { len = at.length; at = template.indexOf(at); } includeDiagnostic(diagnostics(template), message, at, len); } describe('regression', () => { it('should be able to return diagnostics if reflector gets invalidated', () => { const fileName = '/app/main.ts'; ngService.getDiagnostics(fileName); (ngHost as any)._reflector = null; ngService.getDiagnostics(fileName); }); }); describe('with $event', () => { it('should accept an event', () => { accept('
Using an invalid pipe {{data | dat}}
'}) export class MyComponent { data = 'some data'; }`; addCode(code, fileName => { const diagnostic = ngService.getDiagnostics(fileName).filter(d => d.message.indexOf('pipe') > 0)[0]; expect(diagnostic).not.toBeUndefined(); expect(diagnostic.span.end - diagnostic.span.start).toBeLessThan(11); }); }); // Issue #15460 it('should be able to find members defined on an ancestor type', () => { const app_component = ` import { Component } from '@angular/core'; import { NgForm } from '@angular/common'; @Component({ selector: 'example-app', template: \`First name value: {{ first.value }}
First name valid: {{ first.valid }}
Form value: {{ f.value | json }}
Form valid: {{ f.valid }}
\`, }) export class AppComponent { onSubmit(form: NgForm) {} } `; const fileName = '/app/app.component.ts'; mockHost.override(fileName, app_component); const diagnostic = ngService.getDiagnostics(fileName); expect(diagnostic).toEqual([]); }); it('should report an error for invalid providers', () => { addCode( ` @Component({ template: '', providers: [null] }) export class MyComponent {} `, fileName => { const diagnostics = ngService.getDiagnostics(fileName); const expected = diagnostics.find(d => d.message.startsWith('Invalid providers for')); const notExpected = diagnostics.find(d => d.message.startsWith('Cannot read property')); expect(expected).toBeDefined(); expect(notExpected).toBeUndefined(); }); }); function addCode(code: string, cb: (fileName: string, content?: string) => void) { const fileName = '/app/app.component.ts'; const originalContent = mockHost.getFileContent(fileName); const newContent = originalContent + code; mockHost.override(fileName, originalContent + code); ngHost.updateAnalyzedModules(); try { cb(fileName, newContent); } finally { mockHost.override(fileName, undefined); } } function onlyModuleDiagnostics(diagnostics: Diagnostics) { // Expect only the 'MyComponent' diagnostic expect(diagnostics.length).toBe(1); if (diagnostics.length > 1) { for (const diagnostic of diagnostics) { if (diagnostic.message.indexOf('MyComponent') >= 0) continue; console.error(`(${diagnostic.span.start}:${diagnostic.span.end}): ${diagnostic.message}`); } return; } expect(diagnostics[0].message.indexOf('MyComponent') >= 0).toBeTruthy(); } }); });