| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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'; | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  | import {Diagnostics, LanguageService} from '../src/types'; | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | import {TypeScriptServiceHost} from '../src/typescript_host'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {toh} from './test_data'; | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  | import {MockTypescriptHost, diagnosticMessageContains, findDiagnostic, includeDiagnostic, noDiagnostics} from './test_utils'; | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | describe('diagnostics', () => { | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |   let mockHost: MockTypescriptHost; | 
					
						
							|  |  |  |   let ngHost: TypeScriptServiceHost; | 
					
						
							|  |  |  |   let ngService: LanguageService; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     mockHost = new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], toh); | 
					
						
							|  |  |  |     const documentRegistry = ts.createDocumentRegistry(); | 
					
						
							|  |  |  |     const service = ts.createLanguageService(mockHost, documentRegistry); | 
					
						
							|  |  |  |     ngHost = new TypeScriptServiceHost(mockHost, service); | 
					
						
							|  |  |  |     ngService = createLanguageService(ngHost); | 
					
						
							|  |  |  |     ngHost.setSite(ngService); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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); | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |         return ngService.getDiagnostics(fileName) !; | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       } finally { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |         mockHost.override(fileName, undefined !); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-28 09:37:24 -07:00
										 |  |  |     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); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-06-19 10:07:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // #17611
 | 
					
						
							|  |  |  |       it('should not report diagnostic on iteration of any', | 
					
						
							|  |  |  |          () => { accept('<div *ngFor="let value of anyValue">{{value.someField}}</div>'); }); | 
					
						
							| 
									
										
										
										
											2017-03-28 09:37:24 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |     describe('with $event', () => { | 
					
						
							|  |  |  |       it('should accept an event', | 
					
						
							|  |  |  |          () => { accept('<div (click)="myClick($event)">Click me!</div>'); }); | 
					
						
							|  |  |  |       it('should reject it when not in an event binding', () => { | 
					
						
							|  |  |  |         reject('<div [tabIndex]="$event"></div>', '\'$event\' is not defined', '$event'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('with regression tests', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not crash with a incomplete *ngFor', () => { | 
					
						
							|  |  |  |       expect(() => { | 
					
						
							|  |  |  |         const code = | 
					
						
							|  |  |  |             '\n@Component({template: \'<div *ngFor></div> ~{after-div}\'}) export class MyComponent {}'; | 
					
						
							|  |  |  |         addCode(code, fileName => { ngService.getDiagnostics(fileName); }); | 
					
						
							|  |  |  |       }).not.toThrow(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should report a component not in a module', () => { | 
					
						
							|  |  |  |       const code = '\n@Component({template: \'<div></div>\'}) export class MyComponent {}'; | 
					
						
							|  |  |  |       addCode(code, (fileName, content) => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |         const offset = content !.lastIndexOf('@Component') + 1; | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |         const len = 'Component'.length; | 
					
						
							|  |  |  |         includeDiagnostic( | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |             diagnostics !, 'Component \'MyComponent\' is not included in a module', offset, len); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not report an error for a form\'s host directives', () => { | 
					
						
							|  |  |  |       const code = '\n@Component({template: \'<form></form>\'}) export class MyComponent {}'; | 
					
						
							|  |  |  |       addCode(code, (fileName, content) => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |         expectOnlyModuleDiagnostics(diagnostics); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not throw getting diagnostics for an index expression', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: '<a *ngIf="(auth.isAdmin | async) || (event.leads && event.leads[(auth.uid | async)])"></a>'}) export class MyComponent {}`; | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           code, fileName => { expect(() => ngService.getDiagnostics(fileName)).not.toThrow(); }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not throw using a directive with no value', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: '<form><input [(ngModel)]="name" required /></form>'}) export class MyComponent { name = 'some name'; }`; | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           code, fileName => { expect(() => ngService.getDiagnostics(fileName)).not.toThrow(); }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should report an error for invalid metadata', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: '', provider: [{provide: 'foo', useFactor: () => 'foo' }]}) export class MyComponent { name = 'some name'; }`; | 
					
						
							|  |  |  |       addCode(code, (fileName, content) => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							|  |  |  |         includeDiagnostic( | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |             diagnostics !, 'Function expressions are not supported in decorators', '() => \'foo\'', | 
					
						
							|  |  |  |             content); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-06 09:56:30 -08:00
										 |  |  |     it('should not throw for an invalid class', () => { | 
					
						
							|  |  |  |       const code = ` @Component({template: ''}) class`; | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           code, fileName => { expect(() => ngService.getDiagnostics(fileName)).not.toThrow(); }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 16:42:20 -08:00
										 |  |  |     it('should not report an error for sub-types of string', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: \`<div *ngIf="something === 'foo'"></div>\`}) export class MyComponent { something: 'foo' | 'bar'; }`; | 
					
						
							|  |  |  |       addCode(code, fileName => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |         expectOnlyModuleDiagnostics(diagnostics); | 
					
						
							| 
									
										
										
										
											2016-12-12 16:42:20 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-12-13 11:20:45 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should report a warning if an event results in a callable expression', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: \`<div (click)="onClick"></div>\`}) export class MyComponent { onClick() { } }`; | 
					
						
							|  |  |  |       addCode(code, (fileName, content) => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							|  |  |  |         includeDiagnostic( | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |             diagnostics !, 'Unexpected callable expression. Expected a method call', 'onClick', | 
					
						
							| 
									
										
										
										
											2016-12-13 11:20:45 -08:00
										 |  |  |             content); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-12-12 18:11:56 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // #13412
 | 
					
						
							|  |  |  |     it('should not report an error for using undefined', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: \`<div *ngIf="something === undefined"></div>\`}) export class MyComponent { something = 'foo'; }})`; | 
					
						
							|  |  |  |       addCode(code, fileName => { | 
					
						
							|  |  |  |         const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |         expectOnlyModuleDiagnostics(diagnostics); | 
					
						
							| 
									
										
										
										
											2016-12-12 18:11:56 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-12-12 15:59:12 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Issue #13326
 | 
					
						
							|  |  |  |     it('should report a narrow span for invalid pipes', () => { | 
					
						
							|  |  |  |       const code = | 
					
						
							|  |  |  |           ` @Component({template: '<p> Using an invalid pipe {{data | dat}} </p>'}) export class MyComponent { data = 'some data'; }`; | 
					
						
							|  |  |  |       addCode(code, fileName => { | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |         const diagnostic = findDiagnostic(ngService.getDiagnostics(fileName) !, 'pipe') !; | 
					
						
							| 
									
										
										
										
											2016-12-12 15:59:12 -08:00
										 |  |  |         expect(diagnostic).not.toBeUndefined(); | 
					
						
							|  |  |  |         expect(diagnostic.span.end - diagnostic.span.start).toBeLessThan(11); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-03-29 16:14:37 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-22 12:09:49 -08:00
										 |  |  |     // Issue #19406
 | 
					
						
							|  |  |  |     it('should allow empty template', () => { | 
					
						
							|  |  |  |       const appComponent = `
 | 
					
						
							|  |  |  |         import { Component } from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           template : '', | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class AppComponent {} | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const fileName = '/app/app.component.ts'; | 
					
						
							|  |  |  |       mockHost.override(fileName, appComponent); | 
					
						
							|  |  |  |       const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							|  |  |  |       expect(diagnostics).toEqual([]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-29 16:14:37 -07:00
										 |  |  |     // 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: \`
 | 
					
						
							|  |  |  |              <form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate> | 
					
						
							|  |  |  |               <input name="first" ngModel required #first="ngModel"> | 
					
						
							|  |  |  |               <input name="last" ngModel> | 
					
						
							|  |  |  |               <button>Submit</button> | 
					
						
							|  |  |  |             </form> | 
					
						
							|  |  |  |             <p>First name value: {{ first.value }}</p> | 
					
						
							|  |  |  |             <p>First name valid: {{ first.valid }}</p> | 
					
						
							|  |  |  |             <p>Form value: {{ f.value | json }}</p> | 
					
						
							|  |  |  |             <p>Form valid: {{ f.valid }}</p> | 
					
						
							|  |  |  |          \`,
 | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         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([]); | 
					
						
							| 
									
										
										
										
											2017-04-04 08:30:38 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should report an error for invalid providers', () => { | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           template: '', | 
					
						
							|  |  |  |           providers: [null] | 
					
						
							|  |  |  |        }) | 
					
						
							|  |  |  |        export class MyComponent {} | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |           fileName => { | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |             const diagnostics = ngService.getDiagnostics(fileName) !; | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |             const expected = findDiagnostic(diagnostics, 'Invalid providers for'); | 
					
						
							|  |  |  |             const notExpected = findDiagnostic(diagnostics, 'Cannot read property'); | 
					
						
							| 
									
										
										
										
											2017-04-04 08:30:38 -07:00
										 |  |  |             expect(expected).toBeDefined(); | 
					
						
							|  |  |  |             expect(notExpected).toBeUndefined(); | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2017-04-04 11:37:06 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Issue #15768
 | 
					
						
							|  |  |  |     it('should be able to parse a template reference', () => { | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'my-component', | 
					
						
							|  |  |  |           template: \`
 | 
					
						
							|  |  |  |             <div *ngIf="comps | async; let comps; else loading"> | 
					
						
							|  |  |  |             </div> | 
					
						
							| 
									
										
										
										
											2018-01-05 12:33:26 -08:00
										 |  |  |             <ng-template #loading>Loading comps...</ng-template> | 
					
						
							| 
									
										
										
										
											2017-04-04 11:37:06 -07:00
										 |  |  |           \`
 | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class MyComponent {} | 
					
						
							|  |  |  |       `,
 | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |           fileName => expectOnlyModuleDiagnostics(ngService.getDiagnostics(fileName))); | 
					
						
							| 
									
										
										
										
											2016-12-12 16:42:20 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 10:31:01 -07:00
										 |  |  |     // Issue #15625
 | 
					
						
							|  |  |  |     it('should not report errors for localization syntax', () => { | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'my-component', | 
					
						
							|  |  |  |             template: \`
 | 
					
						
							|  |  |  |             <div> | 
					
						
							|  |  |  |                 {fieldCount, plural, =0 {no fields} =1 {1 field} other {{{fieldCount}} fields}} | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |             \`
 | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MyComponent { | 
					
						
							|  |  |  |             fieldCount: number; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |           fileName => { | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |             const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							| 
									
										
										
										
											2017-04-10 15:10:34 -07:00
										 |  |  |             expectOnlyModuleDiagnostics(diagnostics); | 
					
						
							| 
									
										
										
										
											2017-04-04 10:31:01 -07:00
										 |  |  |           }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 15:10:34 -07:00
										 |  |  |     // Issue #15885
 | 
					
						
							|  |  |  |     it('should be able to remove null and undefined from a type', () => { | 
					
						
							|  |  |  |       mockHost.overrideOptions(options => { | 
					
						
							|  |  |  |         options.strictNullChecks = true; | 
					
						
							|  |  |  |         return options; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       addCode( | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'my-component', | 
					
						
							|  |  |  |           template: \` {{test?.a}}
 | 
					
						
							|  |  |  |           \`
 | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class MyComponent { | 
					
						
							|  |  |  |           test: {a: number, b: number} | null = { | 
					
						
							|  |  |  |             a: 1, | 
					
						
							|  |  |  |             b: 2 | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |           fileName => expectOnlyModuleDiagnostics(ngService.getDiagnostics(fileName))); | 
					
						
							| 
									
										
										
										
											2017-04-13 16:19:59 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to resolve modules using baseUrl', () => { | 
					
						
							|  |  |  |       const app_component = `
 | 
					
						
							|  |  |  |         import { Component } from '@angular/core'; | 
					
						
							|  |  |  |         import { NgForm } from '@angular/common'; | 
					
						
							|  |  |  |         import { Server } from 'app/server'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'example-app', | 
					
						
							|  |  |  |           template: '...', | 
					
						
							|  |  |  |           providers: [Server] | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class AppComponent { | 
					
						
							|  |  |  |           onSubmit(form: NgForm) {} | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const app_server = `
 | 
					
						
							|  |  |  |         export class Server {} | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const fileName = '/app/app.component.ts'; | 
					
						
							|  |  |  |       mockHost.override(fileName, app_component); | 
					
						
							|  |  |  |       mockHost.addScript('/other/files/app/server.ts', app_server); | 
					
						
							|  |  |  |       mockHost.overrideOptions(options => { | 
					
						
							|  |  |  |         options.baseUrl = '/other/files'; | 
					
						
							|  |  |  |         return options; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const diagnostic = ngService.getDiagnostics(fileName); | 
					
						
							|  |  |  |       expect(diagnostic).toEqual([]); | 
					
						
							| 
									
										
										
										
											2017-04-10 15:10:34 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 09:30:34 -07:00
										 |  |  |     it('should not report errors for using the now removed OpaqueToken (support for v4)', () => { | 
					
						
							|  |  |  |       const app_component = `
 | 
					
						
							|  |  |  |         import { Component, Inject, OpaqueToken } from '@angular/core'; | 
					
						
							|  |  |  |         import { NgForm } from '@angular/common'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         export const token = new OpaqueToken(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'example-app', | 
					
						
							|  |  |  |           template: '...' | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class AppComponent { | 
					
						
							|  |  |  |           constructor (@Inject(token) value: string) {} | 
					
						
							|  |  |  |           onSubmit(form: NgForm) {} | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const fileName = '/app/app.component.ts'; | 
					
						
							|  |  |  |       mockHost.override(fileName, app_component); | 
					
						
							|  |  |  |       const diagnostics = ngService.getDiagnostics(fileName); | 
					
						
							|  |  |  |       expect(diagnostics).toEqual([]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2016-12-02 14:34:16 -08:00
										 |  |  |       ngHost.updateAnalyzedModules(); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       try { | 
					
						
							|  |  |  |         cb(fileName, newContent); | 
					
						
							|  |  |  |       } finally { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:57:32 -07:00
										 |  |  |         mockHost.override(fileName, undefined !); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |     function expectOnlyModuleDiagnostics(diagnostics: Diagnostics | undefined) { | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |       // Expect only the 'MyComponent' diagnostic
 | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |       if (!diagnostics) throw new Error('Expecting Diagnostics'); | 
					
						
							| 
									
										
										
										
											2016-12-12 16:42:20 -08:00
										 |  |  |       if (diagnostics.length > 1) { | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |         const unexpectedDiagnostics = | 
					
						
							|  |  |  |             diagnostics.filter(diag => !diagnosticMessageContains(diag.message, 'MyComponent')) | 
					
						
							|  |  |  |                 .map(diag => `(${diag.span.start}:${diag.span.end}): ${diag.message}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (unexpectedDiagnostics.length) { | 
					
						
							|  |  |  |           fail(`Unexpected diagnostics:\n  ${unexpectedDiagnostics.join('\n  ')}`); | 
					
						
							|  |  |  |           return; | 
					
						
							| 
									
										
										
										
											2016-12-12 16:42:20 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-07-06 09:13:25 +03:00
										 |  |  |       expect(diagnostics.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |       expect(diagnosticMessageContains(diagnostics[0].message, 'MyComponent')).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |