build: reformat repo to new clang@1.4.0 (#36628)

PR Close #36628
This commit is contained in:
Joey Perrott
2020-04-13 17:43:52 -07:00
committed by atscott
parent 4b3f9ac739
commit 26f49151e7
1163 changed files with 31727 additions and 24036 deletions

View File

@ -14,17 +14,25 @@ import {obsoleteInIvy} from '@angular/private/testing';
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
class DummyConsole implements Console {
public warnings: string[] = [];
log(message: string) {}
warn(message: string) { this.warnings.push(message); }
warn(message: string) {
this.warnings.push(message);
}
}
function declareTests(config?: {useJit: boolean}) {
@ -40,7 +48,7 @@ function declareTests(config?: {useJit: boolean}) {
const compFixture = TestBed.createComponent(MainComp);
const mainComp: MainComp = compFixture.componentInstance;
expect(compFixture.componentRef.injector.get(ComponentFactoryResolver)).toBe(mainComp.cfr);
const cf = mainComp.cfr.resolveComponentFactory(ChildComp) !;
const cf = mainComp.cfr.resolveComponentFactory(ChildComp)!;
expect(cf.componentType).toBe(ChildComp);
});
@ -52,8 +60,8 @@ function declareTests(config?: {useJit: boolean}) {
const mainComp: CompWithAnalyzeEntryComponentsProvider = compFixture.componentInstance;
const cfr: ComponentFactoryResolver =
compFixture.componentRef.injector.get(ComponentFactoryResolver);
expect(cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp);
expect(cfr.resolveComponentFactory(NestedChildComp) !.componentType).toBe(NestedChildComp);
expect(cfr.resolveComponentFactory(ChildComp)!.componentType).toBe(ChildComp);
expect(cfr.resolveComponentFactory(NestedChildComp)!.componentType).toBe(NestedChildComp);
});
it('should be able to get a component form a parent component (view hierarchy)', () => {
@ -63,10 +71,10 @@ function declareTests(config?: {useJit: boolean}) {
const childCompEl = compFixture.debugElement.children[0];
const childComp: ChildComp = childCompEl.componentInstance;
// declared on ChildComp directly
expect(childComp.cfr.resolveComponentFactory(NestedChildComp) !.componentType)
expect(childComp.cfr.resolveComponentFactory(NestedChildComp)!.componentType)
.toBe(NestedChildComp);
// inherited from MainComp
expect(childComp.cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp);
expect(childComp.cfr.resolveComponentFactory(ChildComp)!.componentType).toBe(ChildComp);
});
obsoleteInIvy('In Ivy, the ComponentFactoryResolver can resolve any component factory')
@ -79,12 +87,11 @@ function declareTests(config?: {useJit: boolean}) {
const compFixture = TestBed.createComponent(MainComp);
const nestedChildCompEl = compFixture.debugElement.children[0].children[0];
const nestedChildComp: NestedChildComp = nestedChildCompEl.componentInstance;
expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp) !.componentType)
expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp)!.componentType)
.toBe(ChildComp);
expect(() => nestedChildComp.cfr.resolveComponentFactory(NestedChildComp))
.toThrow(noComponentFactoryError(NestedChildComp));
});
});
}

View File

@ -17,8 +17,7 @@ class DirectiveA {
@Directive({selector: '[directiveB]'})
class DirectiveB {
@HostBinding('title')
title = 'DirectiveB Title';
@HostBinding('title') title = 'DirectiveB Title';
}
@Component({selector: 'component-a', template: 'ComponentA Template'})
@ -34,8 +33,7 @@ class ComponentWithNoAnnotation extends ComponentA {}
@Directive({selector: '[directiveExtendsComponent]'})
class DirectiveExtendsComponent extends ComponentA {
@HostBinding('title')
title = 'DirectiveExtendsComponent Title';
@HostBinding('title') title = 'DirectiveExtendsComponent Title';
}
class DirectiveWithNoAnnotation extends DirectiveB {}

View File

@ -7,7 +7,7 @@
*/
import {CommonModule, DOCUMENT, ɵgetDOM as getDOM} from '@angular/common';
import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleRef, OnDestroy, SkipSelf, ViewRef, ɵivyEnabled as ivyEnabled} from '@angular/core';
import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, SkipSelf, ViewRef, ɵivyEnabled as ivyEnabled} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
import {getDebugContext} from '@angular/core/src/errors';
import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';
@ -17,7 +17,7 @@ import {TemplateRef} from '@angular/core/src/linker/template_ref';
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';
import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';
import {TestBed, async, fakeAsync, getTestBed, tick} from '@angular/core/testing';
import {async, fakeAsync, getTestBed, TestBed, tick} from '@angular/core/testing';
import {createMouseEvent, dispatchEvent, el, isCommentNode} from '@angular/platform-browser/testing/src/browser_util';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing';
@ -27,16 +27,23 @@ import {stringify} from '../../src/util/stringify';
const ANCHOR_ELEMENT = new InjectionToken('AnchorElement');
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
function declareTests(config?: {useJit: boolean}) {
describe('integration tests', function() {
beforeEach(() => { TestBed.configureCompiler({...config}); });
beforeEach(() => {
TestBed.configureCompiler({...config});
});
describe('react to record changes', function() {
it('should consume text node changes', () => {
@ -55,7 +62,7 @@ function declareTests(config?: {useJit: boolean}) {
const template = '<div>{{null}}{{ctxProp}}</div>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
fixture.componentInstance.ctxProp = null !;
fixture.componentInstance.ctxProp = null!;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
@ -133,7 +140,7 @@ function declareTests(config?: {useJit: boolean}) {
fixture.detectChanges();
expect(fixture.debugElement.children[0].nativeElement.getAttribute('foo')).toEqual('bar');
fixture.componentInstance.ctxProp = null !;
fixture.componentInstance.ctxProp = null!;
fixture.detectChanges();
expect(fixture.debugElement.children[0].nativeElement.hasAttribute('foo')).toBeFalsy();
});
@ -148,7 +155,7 @@ function declareTests(config?: {useJit: boolean}) {
fixture.detectChanges();
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('10px');
fixture.componentInstance.ctxProp = null !;
fixture.componentInstance.ctxProp = null!;
fixture.detectChanges();
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('');
});
@ -265,7 +272,7 @@ function declareTests(config?: {useJit: boolean}) {
fixture.componentInstance.ctxProp = 'a';
fixture.detectChanges();
const dir = fixture.debugElement.children[0].references !['dir'];
const dir = fixture.debugElement.children[0].references!['dir'];
expect(dir.dirProp).toEqual('aa');
});
});
@ -344,7 +351,7 @@ function declareTests(config?: {useJit: boolean}) {
it('should display correct error message for uninitialized @Output', () => {
@Component({selector: 'my-uninitialized-output', template: '<p>It works!</p>'})
class UninitializedOutputComp {
@Output() customEvent !: EventEmitter<any>;
@Output() customEvent!: EventEmitter<any>;
}
const template =
@ -406,7 +413,7 @@ function declareTests(config?: {useJit: boolean}) {
ngIfEl.childNodes
.find(
debugElement => debugElement.nativeNode.nodeType ===
Node.COMMENT_NODE) !.injector.get(SomeViewport);
Node.COMMENT_NODE)!.injector.get(SomeViewport);
expect(someViewport.container.length).toBe(2);
expect(ngIfEl.children.length).toBe(2);
@ -455,7 +462,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
expect(fixture.debugElement.children[0].children[0].references !['alice'])
expect(fixture.debugElement.children[0].children[0].references!['alice'])
.toBeAnInstanceOf(ChildComp);
});
@ -465,7 +472,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
expect(fixture.debugElement.children[0].children[0].references !['localdir'])
expect(fixture.debugElement.children[0].children[0].references!['localdir'])
.toBeAnInstanceOf(ExportDir);
});
@ -477,9 +484,9 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
expect(fixture.debugElement.children[0].references !['x'])
expect(fixture.debugElement.children[0].references!['x'])
.toBeAnInstanceOf(DirectiveWithMultipleExportAsNames);
expect(fixture.debugElement.children[0].references !['y'])
expect(fixture.debugElement.children[0].references!['y'])
.toBeAnInstanceOf(DirectiveWithMultipleExportAsNames);
});
@ -505,8 +512,8 @@ function declareTests(config?: {useJit: boolean}) {
const pEl = fixture.debugElement.children[0];
const alice = pEl.children[0].references !['alice'];
const bob = pEl.children[1].references !['bob'];
const alice = pEl.children[0].references!['alice'];
const bob = pEl.children[1].references!['bob'];
expect(alice).toBeAnInstanceOf(ChildComp);
expect(bob).toBeAnInstanceOf(ChildComp);
expect(alice).not.toBe(bob);
@ -518,8 +525,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
expect(fixture.debugElement.children[0].references !['alice'])
.toBeAnInstanceOf(ChildComp);
expect(fixture.debugElement.children[0].references!['alice']).toBeAnInstanceOf(ChildComp);
});
it('should assign the element instance to a user-defined variable', () => {
@ -528,7 +534,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const value = fixture.debugElement.children[0].children[0].references !['alice'];
const value = fixture.debugElement.children[0].children[0].references!['alice'];
expect(value).not.toBe(null);
expect(value.tagName.toLowerCase()).toEqual('div');
});
@ -540,7 +546,7 @@ function declareTests(config?: {useJit: boolean}) {
MyComp, {set: {template: '<ng-template ref-alice></ng-template>'}})
.createComponent(MyComp);
const value = fixture.debugElement.childNodes[0].references !['alice'];
const value = fixture.debugElement.childNodes[0].references!['alice'];
expect(value.createEmbeddedView).toBeTruthy();
});
@ -550,7 +556,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
expect(fixture.debugElement.children[0].children[0].references !['superAlice'])
expect(fixture.debugElement.children[0].children[0].references!['superAlice'])
.toBeAnInstanceOf(ChildComp);
});
});
@ -573,14 +579,13 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('OnPush components', () => {
it('should use ChangeDetectorRef to manually request a check', () => {
TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithRef]]]});
const template = '<push-cmp-with-ref #cmp></push-cmp-with-ref>';
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const cmp = fixture.debugElement.children[0].references !['cmp'];
const cmp = fixture.debugElement.children[0].references!['cmp'];
fixture.detectChanges();
expect(cmp.numberOfChecks).toEqual(1);
@ -601,7 +606,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const cmp = fixture.debugElement.children[0].references !['cmp'];
const cmp = fixture.debugElement.children[0].references!['cmp'];
fixture.componentInstance.ctxProp = 'one';
fixture.detectChanges();
@ -675,7 +680,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const cmp = fixture.debugElement.children[0].references !['cmp'];
const cmp = fixture.debugElement.children[0].references!['cmp'];
fixture.componentInstance.ctxProp = 'one';
fixture.detectChanges();
@ -695,7 +700,7 @@ function declareTests(config?: {useJit: boolean}) {
tick();
const cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references !['cmp'];
const cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references!['cmp'];
fixture.detectChanges();
expect(cmp.numberOfChecks).toEqual(1);
@ -726,7 +731,7 @@ function declareTests(config?: {useJit: boolean}) {
const fixture = TestBed.createComponent(MyComp);
const childComponent =
fixture.debugElement.children[0].children[0].children[0].references !['child'];
fixture.debugElement.children[0].children[0].children[0].references!['child'];
expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);
});
@ -748,7 +753,7 @@ function declareTests(config?: {useJit: boolean}) {
const tc = fixture.debugElement.children[0].children[0].children[0];
const childComponent = tc.references !['child'];
const childComponent = tc.references!['child'];
expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);
});
@ -795,7 +800,7 @@ function declareTests(config?: {useJit: boolean}) {
})
.createComponent(MyComp);
const tc = fixture.debugElement.childNodes.find(
debugElement => debugElement.nativeNode.nodeType === Node.COMMENT_NODE) !;
debugElement => debugElement.nativeNode.nodeType === Node.COMMENT_NODE)!;
const emitter = tc.injector.get(DirectiveEmittingEvent);
const myComp = fixture.debugElement.injector.get(MyComp);
@ -827,8 +832,11 @@ function declareTests(config?: {useJit: boolean}) {
expect(dir.control).toEqual('one');
dir.controlChange.subscribe(
{next: () => { expect(fixture.componentInstance.ctxProp).toEqual('two'); }});
dir.controlChange.subscribe({
next: () => {
expect(fixture.componentInstance.ctxProp).toEqual('two');
}
});
dir.triggerChange('two');
}));
@ -954,9 +962,11 @@ function declareTests(config?: {useJit: boolean}) {
class DirectiveWithHostListener {
id = 'one';
// TODO(issue/24571): remove '!'.
receivedArgs !: any[];
receivedArgs!: any[];
doIt(...args: any[]) { this.receivedArgs = args; }
doIt(...args: any[]) {
this.receivedArgs = args;
}
}
const fixture =
@ -1239,7 +1249,6 @@ function declareTests(config?: {useJit: boolean}) {
}).toThrowError('Cannot move a destroyed View in a ViewContainer!');
}));
});
});
it('should support static attributes', () => {
@ -1292,7 +1301,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const comp = fixture.debugElement.children[0].children[0].references !['consuming'];
const comp = fixture.debugElement.children[0].children[0].references!['consuming'];
expect(comp.injectable).toBeAnInstanceOf(InjectableService);
});
@ -1308,7 +1317,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(DirectiveProvidingInjectableInView, {set: {template}});
const fixture = TestBed.createComponent(DirectiveProvidingInjectableInView);
const comp = fixture.debugElement.children[0].references !['consuming'];
const comp = fixture.debugElement.children[0].references!['consuming'];
expect(comp.injectable).toBeAnInstanceOf(InjectableService);
});
@ -1336,7 +1345,7 @@ function declareTests(config?: {useJit: boolean}) {
});
const fixture = TestBed.createComponent(MyComp);
const comp = fixture.debugElement.children[0].children[0].references !['dir'];
const comp = fixture.debugElement.children[0].children[0].references!['dir'];
expect(comp.directive.injectable).toBeAnInstanceOf(InjectableService);
});
@ -1386,7 +1395,7 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.overrideComponent(MyComp, {set: {template}});
const fixture = TestBed.createComponent(MyComp);
const providing = fixture.debugElement.children[0].references !['providing'];
const providing = fixture.debugElement.children[0].references!['providing'];
expect(providing.created).toBe(false);
fixture.componentInstance.ctxBoolProp = true;
@ -1469,7 +1478,7 @@ function declareTests(config?: {useJit: boolean}) {
});
it('should use a default element name for components without selectors', () => {
let noSelectorComponentFactory: ComponentFactory<SomeComponent> = undefined !;
let noSelectorComponentFactory: ComponentFactory<SomeComponent> = undefined!;
@Component({template: '----'})
class NoSelectorComponent {
@ -1480,7 +1489,7 @@ function declareTests(config?: {useJit: boolean}) {
constructor(componentFactoryResolver: ComponentFactoryResolver) {
// grab its own component factory
noSelectorComponentFactory =
componentFactoryResolver.resolveComponentFactory(NoSelectorComponent) !;
componentFactoryResolver.resolveComponentFactory(NoSelectorComponent)!;
}
}
@ -1502,8 +1511,9 @@ function declareTests(config?: {useJit: boolean}) {
TestBed.configureTestingModule({declarations: [MyComp, SomeDirectiveMissingAnnotation]});
expect(() => TestBed.createComponent(MyComp))
.toThrowError(
`Unexpected value '${stringify(SomeDirectiveMissingAnnotation)}' declared by the module 'DynamicTestModule'. Please add a @Pipe/@Directive/@Component annotation.`);
.toThrowError(`Unexpected value '${
stringify(
SomeDirectiveMissingAnnotation)}' declared by the module 'DynamicTestModule'. Please add a @Pipe/@Directive/@Component annotation.`);
});
it('should report a meaningful error when a component is missing view annotation', () => {
@ -1822,7 +1832,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(fixture.nativeElement.innerHTML).toContain('ng-reflect-dir-prop="hello"');
fixture.componentInstance.ctxProp = undefined !;
fixture.componentInstance.ctxProp = undefined!;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).not.toContain('ng-reflect-');
@ -1839,7 +1849,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(fixture.nativeElement.innerHTML).toContain('ng-reflect-dir-prop="hello"');
fixture.componentInstance.ctxProp = null !;
fixture.componentInstance.ctxProp = null!;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).not.toContain('ng-reflect-');
@ -1871,7 +1881,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(html).toContain('bindings={');
expect(html).toContain('"ng-reflect-ng-if": "true"');
fixture.componentInstance.ctxBoolProp = undefined !;
fixture.componentInstance.ctxBoolProp = undefined!;
fixture.detectChanges();
html = fixture.nativeElement.innerHTML;
@ -1893,14 +1903,13 @@ function declareTests(config?: {useJit: boolean}) {
expect(html).toContain('bindings={');
expect(html).toContain('"ng-reflect-ng-if": "true"');
fixture.componentInstance.ctxBoolProp = null !;
fixture.componentInstance.ctxBoolProp = null!;
fixture.detectChanges();
html = fixture.nativeElement.innerHTML;
expect(html).toContain('bindings={');
expect(html).toContain('"ng-reflect-ng-if": null');
});
});
describe('property decorators', () => {
@ -2079,7 +2088,6 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('attributes', () => {
it('should support attributes with namespace', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});
const template = '<svg:use xlink:href="#id" />';
@ -2142,7 +2150,9 @@ class ComponentWithCustomInterpolationB {
@Injectable()
class MyService {
greeting: string;
constructor() { this.greeting = 'hello'; }
constructor() {
this.greeting = 'hello';
}
}
@Component({selector: 'simple-imp-cmp', template: ''})
@ -2165,14 +2175,16 @@ class DynamicViewport {
this.injector = Injector.create([{provide: MyService, useValue: myService}], vc.injector);
this.componentFactory =
componentFactoryResolver.resolveComponentFactory(ChildCompUsingService) !;
componentFactoryResolver.resolveComponentFactory(ChildCompUsingService)!;
}
create(): ComponentRef<ChildCompUsingService> {
return this.vc.createComponent(this.componentFactory, this.vc.length, this.injector);
}
insert(viewRef: ViewRef, index?: number): ViewRef { return this.vc.insert(viewRef, index); }
insert(viewRef: ViewRef, index?: number): ViewRef {
return this.vc.insert(viewRef, index);
}
move(viewRef: ViewRef, currentIndex: number): ViewRef {
return this.vc.move(viewRef, currentIndex);
@ -2182,25 +2194,29 @@ class DynamicViewport {
@Directive({selector: '[my-dir]', inputs: ['dirProp: elprop'], exportAs: 'mydir'})
class MyDir {
dirProp: string;
constructor() { this.dirProp = ''; }
constructor() {
this.dirProp = '';
}
}
@Directive({selector: '[my-dir2]', inputs: ['dirProp2: elprop'], exportAs: 'mydir2'})
class MyDir2 {
dirProp2: string;
constructor() { this.dirProp2 = ''; }
constructor() {
this.dirProp2 = '';
}
}
@Directive({selector: '[title]', inputs: ['title']})
class DirectiveWithTitle {
// TODO(issue/24571): remove '!'.
title !: string;
title!: string;
}
@Directive({selector: '[title]', inputs: ['title'], host: {'[title]': 'title'}})
class DirectiveWithTitleAndHostProperty {
// TODO(issue/24571): remove '!'.
title !: string;
title!: string;
}
@Component({selector: 'event-cmp', template: '<div (click)="noop()"></div>'})
@ -2220,7 +2236,9 @@ class PushCmp {
numberOfChecks: number;
prop: any;
constructor() { this.numberOfChecks = 0; }
constructor() {
this.numberOfChecks = 0;
}
noop() {}
@ -2251,7 +2269,9 @@ class PushCmpWithRef {
return 'fixed';
}
propagate() { this.ref.markForCheck(); }
propagate() {
this.ref.markForCheck();
}
}
@Component({
@ -2272,11 +2292,13 @@ class PushCmpWithHostEvent {
class PushCmpWithAsyncPipe {
numberOfChecks: number = 0;
// TODO(issue/24571): remove '!'.
resolve !: (result: any) => void;
resolve!: (result: any) => void;
promise: Promise<any>;
constructor() {
this.promise = new Promise((resolve) => { this.resolve = resolve; });
this.promise = new Promise((resolve) => {
this.resolve = resolve;
});
}
get field() {
@ -2291,7 +2313,11 @@ class MyComp {
ctxNumProp: number;
ctxBoolProp: boolean;
ctxArrProp: number[];
toStringThrow = {toString: function() { throw 'boom'; }};
toStringThrow = {
toString: function() {
throw 'boom';
}
};
constructor() {
this.ctxProp = 'initial value';
@ -2300,7 +2326,9 @@ class MyComp {
this.ctxArrProp = [0, 1, 2];
}
throwError() { throw 'boom'; }
throwError() {
throw 'boom';
}
}
@Component({
@ -2326,7 +2354,9 @@ class ChildCompNoTemplate {
@Component({selector: 'child-cmp-svc', template: '{{ctxProp}}'})
class ChildCompUsingService {
ctxProp: string;
constructor(service: MyService) { this.ctxProp = service.greeting; }
constructor(service: MyService) {
this.ctxProp = service.greeting;
}
}
@Directive({selector: 'some-directive'})
@ -2341,7 +2371,9 @@ class SomeDirectiveMissingAnnotation {}
})
class CompWithHost {
myHost: SomeDirective;
constructor(@Host() someComp: SomeDirective) { this.myHost = someComp; }
constructor(@Host() someComp: SomeDirective) {
this.myHost = someComp;
}
}
@Component({selector: '[child-cmp2]', viewProviders: [MyService]})
@ -2384,7 +2416,9 @@ class NoContext {
@Pipe({name: 'double'})
class DoublePipe implements PipeTransform, OnDestroy {
ngOnDestroy() {}
transform(value: any) { return `${value}${value}`; }
transform(value: any) {
return `${value}${value}`;
}
}
@Directive({selector: '[emitter]', outputs: ['event']})
@ -2397,7 +2431,9 @@ class DirectiveEmittingEvent {
this.event = new EventEmitter();
}
fireEvent(msg: string) { this.event.emit(msg); }
fireEvent(msg: string) {
this.event.emit(msg);
}
}
@Directive({selector: '[update-host-attributes]', host: {'role': 'button'}})
@ -2408,16 +2444,22 @@ class DirectiveUpdatingHostAttributes {
class DirectiveUpdatingHostProperties {
id: string;
constructor() { this.id = 'one'; }
constructor() {
this.id = 'one';
}
}
@Directive({selector: '[listener]', host: {'(event)': 'onEvent($event)'}})
class DirectiveListeningEvent {
msg: string;
constructor() { this.msg = ''; }
constructor() {
this.msg = '';
}
onEvent(msg: string) { this.msg = msg; }
onEvent(msg: string) {
this.msg = msg;
}
}
@Directive({
@ -2431,17 +2473,27 @@ class DirectiveListeningEvent {
})
class DirectiveListeningDomEvent {
eventTypes: string[] = [];
onEvent(eventType: string) { this.eventTypes.push(eventType); }
onWindowEvent(eventType: string) { this.eventTypes.push('window_' + eventType); }
onDocumentEvent(eventType: string) { this.eventTypes.push('document_' + eventType); }
onBodyEvent(eventType: string) { this.eventTypes.push('body_' + eventType); }
onEvent(eventType: string) {
this.eventTypes.push(eventType);
}
onWindowEvent(eventType: string) {
this.eventTypes.push('window_' + eventType);
}
onDocumentEvent(eventType: string) {
this.eventTypes.push('document_' + eventType);
}
onBodyEvent(eventType: string) {
this.eventTypes.push('body_' + eventType);
}
}
let globalCounter = 0;
@Directive({selector: '[listenerother]', host: {'(window:domEvent)': 'onEvent($event.type)'}})
class DirectiveListeningDomEventOther {
eventType: string;
constructor() { this.eventType = ''; }
constructor() {
this.eventType = '';
}
onEvent(eventType: string) {
globalCounter++;
this.eventType = 'other_' + eventType;
@ -2450,18 +2502,22 @@ class DirectiveListeningDomEventOther {
@Directive({selector: '[listenerprevent]', host: {'(click)': 'onEvent($event)'}})
class DirectiveListeningDomEventPrevent {
onEvent(event: any) { return false; }
onEvent(event: any) {
return false;
}
}
@Directive({selector: '[listenernoprevent]', host: {'(click)': 'onEvent($event)'}})
class DirectiveListeningDomEventNoPrevent {
onEvent(event: any) { return true; }
onEvent(event: any) {
return true;
}
}
@Directive({selector: '[id]', inputs: ['id']})
class IdDir {
// TODO(issue/24571): remove '!'.
id !: string;
id!: string;
}
@Directive({selector: '[customEvent]'})
@ -2497,7 +2553,9 @@ class PrivateImpl extends PublicApi {
@Directive({selector: '[needs-public-api]'})
class NeedsPublicApi {
constructor(@Host() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }
constructor(@Host() api: PublicApi) {
expect(api instanceof PrivateImpl).toBe(true);
}
}
class ToolbarContext {
@ -2507,7 +2565,9 @@ class ToolbarContext {
@Directive({selector: '[toolbarpart]'})
class ToolbarPart {
templateRef: TemplateRef<ToolbarContext>;
constructor(templateRef: TemplateRef<ToolbarContext>) { this.templateRef = templateRef; }
constructor(templateRef: TemplateRef<ToolbarContext>) {
this.templateRef = templateRef;
}
}
@Directive({selector: '[toolbarVc]', inputs: ['toolbarVc']})
@ -2525,7 +2585,7 @@ class ToolbarViewContainer {
})
class ToolbarComponent {
// TODO(issue/24571): remove '!'.
@ContentChildren(ToolbarPart) query !: QueryList<ToolbarPart>;
@ContentChildren(ToolbarPart) query!: QueryList<ToolbarPart>;
ctxProp: string = 'hello world';
constructor() {}
@ -2536,7 +2596,9 @@ class DirectiveWithTwoWayBinding {
controlChange = new EventEmitter();
control: any = null;
triggerChange(value: any) { this.controlChange.emit(value); }
triggerChange(value: any) {
this.controlChange.emit(value);
}
}
@Injectable()
@ -2585,7 +2647,9 @@ class DirectiveProvidingInjectableInHostAndView {
class DirectiveConsumingInjectable {
injectable: any;
constructor(@Host() @Inject(InjectableService) injectable: any) { this.injectable = injectable; }
constructor(@Host() @Inject(InjectableService) injectable: any) {
this.injectable = injectable;
}
}
@ -2620,12 +2684,14 @@ class EventBus {
@Directive({
selector: 'grand-parent-providing-event-bus',
providers: [{provide: EventBus, useValue: new EventBus(null !, 'grandparent')}]
providers: [{provide: EventBus, useValue: new EventBus(null!, 'grandparent')}]
})
class GrandParentProvidingEventBus {
bus: EventBus;
constructor(bus: EventBus) { this.bus = bus; }
constructor(bus: EventBus) {
this.bus = bus;
}
}
function createParentBus(peb: EventBus) {
@ -2651,7 +2717,9 @@ class ParentProvidingEventBus {
class ChildConsumingEventBus {
bus: EventBus;
constructor(@SkipSelf() bus: EventBus) { this.bus = bus; }
constructor(@SkipSelf() bus: EventBus) {
this.bus = bus;
}
}
@Directive({selector: '[someImpvp]', inputs: ['someImpvp']})
@ -2695,17 +2763,23 @@ class ComponentWithoutView {
@Directive({selector: '[no-duplicate]'})
class DuplicateDir {
constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'noduplicate'; }
constructor(elRef: ElementRef) {
elRef.nativeElement.textContent += 'noduplicate';
}
}
@Directive({selector: '[no-duplicate]'})
class OtherDuplicateDir {
constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'othernoduplicate'; }
constructor(elRef: ElementRef) {
elRef.nativeElement.textContent += 'othernoduplicate';
}
}
@Directive({selector: 'directive-throwing-error'})
class DirectiveThrowingAnError {
constructor() { throw new Error('BOOM'); }
constructor() {
throw new Error('BOOM');
}
}
@Component({
@ -2721,15 +2795,19 @@ class DirectiveWithPropDecorators {
target: any;
// TODO(issue/24571): remove '!'.
@Input('elProp') dirProp !: string;
@Input('elProp') dirProp!: string;
@Output('elEvent') event = new EventEmitter();
// TODO(issue/24571): remove '!'.
@HostBinding('attr.my-attr') myAttr !: string;
@HostBinding('attr.my-attr') myAttr!: string;
@HostListener('click', ['$event.target'])
onClick(target: any) { this.target = target; }
onClick(target: any) {
this.target = target;
}
fireEvent(msg: any) { this.event.emit(msg); }
fireEvent(msg: any) {
this.event.emit(msg);
}
}
@Component({selector: 'some-cmp'})

View File

@ -10,7 +10,7 @@ import {ResourceLoader} from '@angular/compiler';
import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver';
import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock';
import {Component, Directive, Injectable, NgModule, OnDestroy, Pipe} from '@angular/core';
import {TestBed, async, getTestBed} from '@angular/core/testing';
import {async, getTestBed, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {obsoleteInIvy} from '@angular/private/testing';
@ -32,7 +32,7 @@ import {obsoleteInIvy} from '@angular/private/testing';
}
function expectInstanceCreated(type: any) {
const instance = instances.get(type) !;
const instance = instances.get(type)!;
expect(instance).toBeDefined();
expect(instance.dep instanceof SomeDep).toBe(true);
}
@ -46,7 +46,9 @@ import {obsoleteInIvy} from '@angular/private/testing';
class SomeDirective extends Base {}
class SomePipe extends Base {
transform(value: any) { return value; }
transform(value: any) {
return value;
}
}
class SomeService extends Base {}
@ -138,7 +140,9 @@ import {obsoleteInIvy} from '@angular/private/testing';
createSummaries().then(s => summaries = s);
}));
afterEach(() => { resetTestEnvironmentWithSummaries(); });
afterEach(() => {
resetTestEnvironmentWithSummaries();
});
it('should use directive metadata from summaries', () => {
resetTestEnvironmentWithSummaries(summaries);

View File

@ -15,15 +15,20 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
import {modifiedInIvy} from '@angular/private/testing';
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
function declareTests(config?: {useJit: boolean}) {
describe('<ng-container>', function() {
beforeEach(() => {
TestBed.configureCompiler({...config});
TestBed.configureTestingModule({
@ -140,7 +145,7 @@ function declareTests(config?: {useJit: boolean}) {
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
const q = fixture.debugElement.children[0].references !['q'];
const q = fixture.debugElement.children[0].references!['q'];
fixture.detectChanges();
expect(q.textDirChildren.length).toEqual(1);
@ -153,7 +158,7 @@ function declareTests(config?: {useJit: boolean}) {
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
const q = fixture.debugElement.children[0].references !['q'];
const q = fixture.debugElement.children[0].references!['q'];
fixture.detectChanges();
expect(q.textDirChildren.length).toEqual(1);
@ -170,21 +175,25 @@ class TextDirective {
@Component({selector: 'needs-content-children', template: ''})
class NeedsContentChildren implements AfterContentInit {
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective) textDirChildren !: QueryList<TextDirective>;
@ContentChildren(TextDirective) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
numberOfChildrenAfterContentInit !: number;
numberOfChildrenAfterContentInit!: number;
ngAfterContentInit() { this.numberOfChildrenAfterContentInit = this.textDirChildren.length; }
ngAfterContentInit() {
this.numberOfChildrenAfterContentInit = this.textDirChildren.length;
}
}
@Component({selector: 'needs-view-children', template: '<div text></div>'})
class NeedsViewChildren implements AfterViewInit {
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) textDirChildren !: QueryList<TextDirective>;
@ViewChildren(TextDirective) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
numberOfChildrenAfterViewInit !: number;
numberOfChildrenAfterViewInit!: number;
ngAfterViewInit() { this.numberOfChildrenAfterViewInit = this.textDirChildren.length; }
ngAfterViewInit() {
this.numberOfChildrenAfterViewInit = this.textDirChildren.length;
}
}
@Component({selector: 'simple', template: 'SIMPLE(<ng-content></ng-content>)'})

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, Directive, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, forwardRef, getModuleFactory, ɵivyEnabled as ivyEnabled, ɵɵdefineNgModule as defineNgModule} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, CUSTOM_ELEMENTS_SCHEMA, Directive, forwardRef, getModuleFactory, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, ɵivyEnabled as ivyEnabled, ɵɵdefineNgModule as defineNgModule} from '@angular/core';
import {Console} from '@angular/core/src/console';
import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs';
import {ɵɵdefineInjectable, ɵɵInjectableDef} from '@angular/core/src/di/interface/defs';
import {getNgModuleDef} from '@angular/core/src/render3/definition';
import {NgModuleData} from '@angular/core/src/view/types';
import {tokenKey} from '@angular/core/src/view/util';
import {ComponentFixture, TestBed, inject} from '@angular/core/testing';
import {ComponentFixture, inject, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing';
@ -23,7 +23,9 @@ import {stringify} from '../../src/util/stringify';
class Engine {}
class BrokenEngine {
constructor() { throw new Error('Broken Engine'); }
constructor() {
throw new Error('Broken Engine');
}
}
class DashboardSoftware {}
@ -53,7 +55,9 @@ class CarWithDashboard {
@Injectable()
class SportsCar extends Car {
constructor(engine: Engine) { super(engine); }
constructor(engine: Engine) {
super(engine);
}
}
@Injectable()
@ -79,13 +83,14 @@ class SomeComp {
@Directive({selector: '[someDir]'})
class SomeDirective {
// TODO(issue/24571): remove '!'.
@HostBinding('title') @Input()
someDir !: string;
@HostBinding('title') @Input() someDir!: string;
}
@Pipe({name: 'somePipe'})
class SomePipe {
transform(value: string): any { return `transformed ${value}`; }
transform(value: string): any {
return `transformed ${value}`;
}
}
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
@ -94,10 +99,16 @@ class CompUsingModuleDirectiveAndPipe {
{
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
}
@ -106,7 +117,9 @@ function declareTests(config?: {useJit: boolean}) {
let compiler: Compiler;
let injector: Injector;
beforeEach(() => { TestBed.configureCompiler(config || {}); });
beforeEach(() => {
TestBed.configureCompiler(config || {});
});
beforeEach(inject([Compiler, Injector], (_compiler: Compiler, _injector: Injector) => {
compiler = _compiler;
@ -117,8 +130,7 @@ function declareTests(config?: {useJit: boolean}) {
return compiler.compileModuleSync(moduleType);
}
function createModule<T>(
moduleType: Type<T>, parentInjector?: Injector | null): NgModuleRef<T> {
function createModule<T>(moduleType: Type<T>, parentInjector?: Injector|null): NgModuleRef<T> {
// Read the `ngModuleDef` to cause it to be compiled and any errors thrown.
getNgModuleDef(moduleType);
return createModuleFactory(moduleType).create(parentInjector || null);
@ -136,11 +148,11 @@ function declareTests(config?: {useJit: boolean}) {
const ngModule = createModule(moduleType, injector);
const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType) !;
const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType)!;
const comp = cf.create(Injector.NULL);
return new ComponentFixture(comp, null !, false);
return new ComponentFixture(comp, null!, false);
}
describe('errors', () => {
@ -150,8 +162,8 @@ function declareTests(config?: {useJit: boolean}) {
}
expect(() => createModule(SomeModule))
.toThrowError(
`Can't export directive ${stringify(SomeDirective)} from ${stringify(SomeModule)} as it was neither declared nor imported!`);
.toThrowError(`Can't export directive ${stringify(SomeDirective)} from ${
stringify(SomeModule)} as it was neither declared nor imported!`);
});
it('should error when exporting a pipe that was neither declared nor imported', () => {
@ -160,8 +172,8 @@ function declareTests(config?: {useJit: boolean}) {
}
expect(() => createModule(SomeModule))
.toThrowError(
`Can't export pipe ${stringify(SomePipe)} from ${stringify(SomeModule)} as it was neither declared nor imported!`);
.toThrowError(`Can't export pipe ${stringify(SomePipe)} from ${
stringify(SomeModule)} as it was neither declared nor imported!`);
});
it('should error if a directive is declared in more than 1 module', () => {
@ -177,9 +189,14 @@ function declareTests(config?: {useJit: boolean}) {
expect(() => createModule(Module2))
.toThrowError(
`Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomeDirective)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
`Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${
stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${
stringify(SomeDirective)} to a higher module that imports ${
stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${
stringify(SomeDirective)} then import that NgModule in ${
stringify(Module1)} and ${stringify(Module2)}.`);
});
it('should error if a directive is declared in more than 1 module also if the module declaring it is imported',
@ -194,9 +211,14 @@ function declareTests(config?: {useJit: boolean}) {
expect(() => createModule(Module2))
.toThrowError(
`Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomeDirective)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
`Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${
stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${
stringify(SomeDirective)} to a higher module that imports ${
stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${
stringify(SomeDirective)} then import that NgModule in ${
stringify(Module1)} and ${stringify(Module2)}.`);
});
it('should error if a pipe is declared in more than 1 module', () => {
@ -212,9 +234,13 @@ function declareTests(config?: {useJit: boolean}) {
expect(() => createModule(Module2))
.toThrowError(
`Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomePipe)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
`Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${
stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomePipe)} to a higher module that imports ${
stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${
stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${
stringify(Module2)}.`);
});
it('should error if a pipe is declared in more than 1 module also if the module declaring it is imported',
@ -229,11 +255,14 @@ function declareTests(config?: {useJit: boolean}) {
expect(() => createModule(Module2))
.toThrowError(
`Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomePipe)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
`Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${
stringify(Module1)} and ${stringify(Module2)}! ` +
`Please consider moving ${stringify(SomePipe)} to a higher module that imports ${
stringify(Module1)} and ${stringify(Module2)}. ` +
`You can also create a new NgModule that exports and includes ${
stringify(SomePipe)} then import that NgModule in ${
stringify(Module1)} and ${stringify(Module2)}.`);
});
});
describe('schemas', () => {
@ -361,7 +390,7 @@ function declareTests(config?: {useJit: boolean}) {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType)
.toBe(SomeComp);
expect(ngModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
@ -411,7 +440,7 @@ function declareTests(config?: {useJit: boolean}) {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType)
.toBe(SomeComp);
expect(ngModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
@ -429,7 +458,7 @@ function declareTests(config?: {useJit: boolean}) {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType)
.toBe(SomeComp);
expect(ngModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
@ -447,14 +476,13 @@ function declareTests(config?: {useJit: boolean}) {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType)
.toBe(SomeComp);
expect(ngModule.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(SomeComp)
.componentType)
.toBe(SomeComp);
});
});
describe('bootstrap components', () => {
@ -464,7 +492,7 @@ function declareTests(config?: {useJit: boolean}) {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType)
.toBe(SomeComp);
});
@ -477,7 +505,6 @@ function declareTests(config?: {useJit: boolean}) {
expect(ngModule._bootstrapComponents.length).toBe(1);
expect(ngModule._bootstrapComponents[0]).toBe(SomeComp);
});
});
describe('directives and pipes', () => {
@ -542,7 +569,6 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('import/export', () => {
it('should support exported directives and pipes', () => {
@NgModule({declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]})
class SomeImportedModule {
@ -677,7 +703,7 @@ function declareTests(config?: {useJit: boolean}) {
let moduleType: any = null;
function createInjector(providers: Provider[], parent?: Injector | null): Injector {
function createInjector(providers: Provider[], parent?: Injector|null): Injector {
@NgModule({providers: providers})
class SomeModule {
}
@ -687,8 +713,9 @@ function declareTests(config?: {useJit: boolean}) {
return createModule(SomeModule, parent).injector;
}
it('should provide the module',
() => { expect(createInjector([]).get(moduleType)).toBeAnInstanceOf(moduleType); });
it('should provide the module', () => {
expect(createInjector([]).get(moduleType)).toBeAnInstanceOf(moduleType);
});
it('should instantiate a class without dependencies', () => {
const injector = createInjector([Engine]);
@ -741,7 +768,9 @@ function declareTests(config?: {useJit: boolean}) {
});
it('should provide to a factory', () => {
function sportsCarFactory(e: Engine) { return new SportsCar(e); }
function sportsCarFactory(e: Engine) {
return new SportsCar(e);
}
const injector =
createInjector([Engine, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]);
@ -759,8 +788,7 @@ function declareTests(config?: {useJit: boolean}) {
it('should provide to an alias', () => {
const injector = createInjector([
Engine, {provide: SportsCar, useClass: SportsCar},
{provide: Car, useExisting: SportsCar}
Engine, {provide: SportsCar, useClass: SportsCar}, {provide: Car, useExisting: SportsCar}
]);
const car = injector.get(Car);
@ -879,7 +907,6 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('injecting lazy providers into an eager provider via Injector.get', () => {
it('should inject providers that were declared before it', () => {
@NgModule({
providers: [
@ -920,7 +947,6 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('injecting eager providers into an eager provider via Injector.get', () => {
it('should inject providers that were declared before it', () => {
@NgModule({
providers: [
@ -1039,7 +1065,6 @@ function declareTests(config?: {useJit: boolean}) {
expect(engineFromParent).not.toBe(engineFromChild);
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
});
});
describe('depedency resolution', () => {
@ -1075,7 +1100,9 @@ function declareTests(config?: {useJit: boolean}) {
@NgModule()
class ImportedModule {
constructor() { created = true; }
constructor() {
created = true;
}
}
@NgModule({imports: [ImportedModule]})
@ -1105,7 +1132,9 @@ function declareTests(config?: {useJit: boolean}) {
let destroyed = false;
class SomeInjectable {
ngOnDestroy() { destroyed = true; }
ngOnDestroy() {
destroyed = true;
}
}
@NgModule({providers: [SomeInjectable]})
@ -1125,8 +1154,12 @@ function declareTests(config?: {useJit: boolean}) {
let destroyed = false;
class SomeInjectable {
constructor() { created = true; }
ngOnDestroy() { destroyed = true; }
constructor() {
created = true;
}
ngOnDestroy() {
destroyed = true;
}
}
@NgModule({providers: [SomeInjectable]})
@ -1174,9 +1207,8 @@ function declareTests(config?: {useJit: boolean}) {
}
@NgModule({
imports: [
{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}
]
imports:
[{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}]
})
class SomeModule {
}
@ -1210,9 +1242,8 @@ function declareTests(config?: {useJit: boolean}) {
@NgModule({
providers: [{provide: 'token1', useValue: 'direct'}],
imports: [
{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}
]
imports:
[{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}]
})
class SomeModule {
}

View File

@ -7,7 +7,7 @@
*/
import {CommonModule, ɵgetDOM as getDOM} from '@angular/common';
import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Injector, Input, NO_ERRORS_SCHEMA, NgModule, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Injector, Input, NgModule, NO_ERRORS_SCHEMA, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -50,9 +50,7 @@ describe('projection', () => {
it('should support projecting text interpolation to a non bound element with other bound elements after it',
() => {
TestBed.overrideComponent(Simple, {
set: {
template: 'SIMPLE(<div><ng-content></ng-content></div><div [tabIndex]="0">EL</div>)'
}
set: {template: 'SIMPLE(<div><ng-content></ng-content></div><div [tabIndex]="0">EL</div>)'}
});
TestBed.overrideComponent(MainComp, {set: {template: '<simple>{{text}}</simple>'}});
const main = TestBed.createComponent(MainComp);
@ -244,8 +242,7 @@ describe('projection', () => {
it('should support nesting with content being direct child of a nested component', () => {
TestBed.configureTestingModule({
declarations:
[InnerComponent, InnerInnerComponent, OuterComponent, ManualViewportDirective]
declarations: [InnerComponent, InnerInnerComponent, OuterComponent, ManualViewportDirective]
});
TestBed.overrideComponent(MainComp, {
set: {
@ -304,7 +301,7 @@ describe('projection', () => {
`<ng-content></ng-content>(<ng-template [ngIf]="showing"><ng-content select="div"></ng-content></ng-template>)`
})
class Child {
@Input() showing !: boolean;
@Input() showing!: boolean;
}
@Component({
@ -361,11 +358,13 @@ describe('projection', () => {
});
it('should support moving non projected light dom around', () => {
let sourceDirective: ManualViewportDirective = undefined !;
let sourceDirective: ManualViewportDirective = undefined!;
@Directive({selector: '[manual]'})
class ManualViewportDirective {
constructor(public templateRef: TemplateRef<Object>) { sourceDirective = this; }
constructor(public templateRef: TemplateRef<Object>) {
sourceDirective = this;
}
}
TestBed.configureTestingModule(
@ -594,7 +593,6 @@ describe('projection', () => {
it('should project nodes into nested templates when the main template doesn\'t have <ng-content>',
() => {
@Component({
selector: 'content-in-template',
template:
@ -622,7 +620,6 @@ describe('projection', () => {
});
it('should project nodes into nested templates and the main template', () => {
@Component({
selector: 'content-in-main-and-template',
template:
@ -720,7 +717,6 @@ describe('projection', () => {
});
describe('projectable nodes', () => {
@Component({selector: 'test', template: ''})
class TestComponent {
constructor(public cfr: ComponentFactoryResolver) {}
@ -739,14 +735,20 @@ describe('projection', () => {
class InsertTplRef implements OnInit {
constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {}
ngOnInit() { this._vcRef.createEmbeddedView(this._tplRef); }
ngOnInit() {
this._vcRef.createEmbeddedView(this._tplRef);
}
}
@Directive({selector: '[delayedInsert]', exportAs: 'delayedInsert'})
class DelayedInsertTplRef {
constructor(public vc: ViewContainerRef, public templateRef: TemplateRef<Object>) {}
show() { this.vc.createEmbeddedView(this.templateRef); }
hide() { this.vc.clear(); }
show() {
this.vc.createEmbeddedView(this.templateRef);
}
hide() {
this.vc.clear();
}
}
@NgModule({
@ -893,15 +895,23 @@ class SingleContentTagComponent {
@Directive({selector: '[manual]'})
class ManualViewportDirective {
constructor(public vc: ViewContainerRef, public templateRef: TemplateRef<Object>) {}
show() { this.vc.createEmbeddedView(this.templateRef); }
hide() { this.vc.clear(); }
show() {
this.vc.createEmbeddedView(this.templateRef);
}
hide() {
this.vc.clear();
}
}
@Directive({selector: '[project]'})
class ProjectDirective {
constructor(public vc: ViewContainerRef) {}
show(templateRef: TemplateRef<Object>) { this.vc.createEmbeddedView(templateRef); }
hide() { this.vc.clear(); }
show(templateRef: TemplateRef<Object>) {
this.vc.createEmbeddedView(templateRef);
}
hide() {
this.vc.clear();
}
}
@Component({
@ -1034,5 +1044,5 @@ class CmpA2 {
}
function supportsNativeShadowDOM(): boolean {
return typeof(<any>document.body).createShadowRoot === 'function';
return typeof (<any>document.body).createShadowRoot === 'function';
}

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, asNativeElements, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
import {ElementRef} from '@angular/core/src/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing';
import {Subject} from 'rxjs';
@ -16,7 +16,6 @@ import {Subject} from 'rxjs';
import {stringify} from '../../src/util/stringify';
describe('Query API', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [
MyComp0,
@ -76,7 +75,7 @@ describe('Query API', () => {
const template = '<needs-content-children #q><div text="foo"></div></needs-content-children>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
view.detectChanges();
expect(q.textDirChildren.length).toEqual(1);
expect(q.numberOfChildrenAfterContentInit).toEqual(1);
@ -88,7 +87,7 @@ describe('Query API', () => {
const view = createTestCmp(MyComp0, template);
view.componentInstance.shouldShow = true;
view.detectChanges();
const q: NeedsContentChild = view.debugElement.children[0].references !['q'];
const q: NeedsContentChild = view.debugElement.children[0].references!['q'];
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
view.componentInstance.shouldShow = false;
@ -114,7 +113,7 @@ describe('Query API', () => {
`;
const view = createTestCmp(MyComp0, template);
view.detectChanges();
const q: NeedsContentChild = view.debugElement.children[1].references !['q'];
const q: NeedsContentChild = view.debugElement.children[1].references!['q'];
expect(q.child.text).toEqual('foo');
const directive: DirectiveNeedsContentChild =
view.debugElement.children[0].injector.get(DirectiveNeedsContentChild);
@ -125,7 +124,7 @@ describe('Query API', () => {
const template = '<needs-view-child #q></needs-view-child>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewChild = view.debugElement.children[0].references !['q'];
const q: NeedsViewChild = view.debugElement.children[0].references!['q'];
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
q.shouldShow = false;
@ -140,7 +139,7 @@ describe('Query API', () => {
const template =
'<needs-static-content-view-child #q><div text="contentFoo"></div></needs-static-content-view-child>';
const view = createTestCmp(MyComp0, template);
const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references !['q'];
const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references!['q'];
expect(q.contentChild.text).toBeFalsy();
expect(q.viewChild.text).toBeFalsy();
@ -161,7 +160,7 @@ describe('Query API', () => {
const view = TestBed.createComponent(MyComp0);
view.detectChanges();
const q: NeedsViewChild = view.debugElement.children[0].references !['q'];
const q: NeedsViewChild = view.debugElement.children[0].references!['q'];
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
q.shouldShow = false;
@ -252,8 +251,8 @@ describe('Query API', () => {
const template = '<has-null-query-condition></has-null-query-condition>';
TestBed.overrideComponent(MyCompBroken0, {set: {template}});
expect(() => TestBed.createComponent(MyCompBroken0))
.toThrowError(
`Can't construct a query for the property "errorTrigger" of "${stringify(HasNullQueryCondition)}" since the query selector wasn't defined.`);
.toThrowError(`Can't construct a query for the property "errorTrigger" of "${
stringify(HasNullQueryCondition)}" since the query selector wasn't defined.`);
});
});
@ -422,7 +421,7 @@ describe('Query API', () => {
'</needs-query>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
q.query.changes.subscribe({
next: () => {
@ -444,11 +443,13 @@ describe('Query API', () => {
let isQueryListCompleted = false;
const q: NeedsQuery = view.debugElement.children[0].references !['q'];
const q: NeedsQuery = view.debugElement.children[0].references!['q'];
const changes = <Subject<any>>q.query.changes;
expect(q.query.length).toEqual(1);
expect(changes.closed).toBeFalsy();
changes.subscribe(() => {}, () => {}, () => { isQueryListCompleted = true; });
changes.subscribe(() => {}, () => {}, () => {
isQueryListCompleted = true;
});
view.componentInstance.shouldShow = false;
view.detectChanges();
@ -457,7 +458,7 @@ describe('Query API', () => {
view.componentInstance.shouldShow = true;
view.detectChanges();
const q2: NeedsQuery = view.debugElement.children[0].references !['q'];
const q2: NeedsQuery = view.debugElement.children[0].references!['q'];
expect(q2.query.length).toEqual(1);
expect(changes.closed).toBeTruthy();
@ -472,7 +473,7 @@ describe('Query API', () => {
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-ref-binding>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
view.componentInstance.list = ['1d', '2d'];
view.detectChanges();
@ -486,7 +487,7 @@ describe('Query API', () => {
'<div text="two" #textLabel2="textDir"></div>' +
'</needs-query-by-ref-bindings>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
expect(q.query.first.text).toEqual('one');
expect(q.query.last.text).toEqual('two');
@ -497,7 +498,7 @@ describe('Query API', () => {
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-ref-binding>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
view.componentInstance.list = ['1d', '2d'];
view.detectChanges();
@ -513,7 +514,7 @@ describe('Query API', () => {
'</div>' +
'</needs-query-by-ref-binding>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
view.componentInstance.list = ['1d', '2d'];
view.detectChanges();
@ -534,14 +535,14 @@ describe('Query API', () => {
const template = '<needs-view-query-by-ref-binding #q></needs-view-query-by-ref-binding>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryByLabel = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryByLabel = view.debugElement.children[0].references!['q'];
expect(q.query.first.nativeElement).toHaveText('text');
});
it('should contain all child directives in the view dom', () => {
const template = '<needs-view-children #q></needs-view-children>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
expect(q.textDirChildren.length).toEqual(1);
expect(q.numberOfChildrenAfterViewInit).toEqual(1);
});
@ -551,21 +552,21 @@ describe('Query API', () => {
it('should contain all the elements in the view with that have the given directive', () => {
const template = '<needs-view-query #q><div text="ignoreme"></div></needs-view-query>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQuery = view.debugElement.children[0].references !['q'];
const q: NeedsViewQuery = view.debugElement.children[0].references!['q'];
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
});
it('should not include directive present on the host element', () => {
const template = '<needs-view-query #q text="self"></needs-view-query>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQuery = view.debugElement.children[0].references !['q'];
const q: NeedsViewQuery = view.debugElement.children[0].references!['q'];
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
});
it('should reflect changes in the component', () => {
const template = '<needs-view-query-if #q></needs-view-query-if>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryIf = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryIf = view.debugElement.children[0].references!['q'];
expect(q.query.length).toBe(0);
q.show = true;
@ -577,7 +578,7 @@ describe('Query API', () => {
it('should not be affected by other changes in the component', () => {
const template = '<needs-view-query-nested-if #q></needs-view-query-nested-if>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references!['q'];
expect(q.query.length).toEqual(1);
expect(q.query.first.text).toEqual('1');
@ -592,7 +593,7 @@ describe('Query API', () => {
() => {
const template = '<needs-view-query-order #q></needs-view-query-order>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryOrder = view.debugElement.children[0].references!['q'];
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
@ -605,7 +606,7 @@ describe('Query API', () => {
() => {
const template = '<needs-view-query-order-with-p #q></needs-view-query-order-with-p>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references!['q'];
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
q.list = ['-3', '2'];
@ -616,7 +617,7 @@ describe('Query API', () => {
it('should handle long ngFor cycles', () => {
const template = '<needs-view-query-order #q></needs-view-query-order>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q'];
const q: NeedsViewQueryOrder = view.debugElement.children[0].references!['q'];
// no significance to 50, just a reasonably large cycle.
for (let i = 0; i < 50; i++) {
@ -630,7 +631,7 @@ describe('Query API', () => {
it('should support more than three queries', () => {
const template = '<needs-four-queries #q><div text="1"></div></needs-four-queries>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
expect(q.query1).toBeDefined();
expect(q.query2).toBeDefined();
expect(q.query3).toBeDefined();
@ -643,7 +644,7 @@ describe('Query API', () => {
const template =
'<manual-projecting #q><ng-template><div text="1"></div></ng-template></manual-projecting>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
expect(q.query.length).toBe(0);
q.create();
@ -665,7 +666,7 @@ describe('Query API', () => {
</ng-template>
</manual-projecting>`;
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'] as ManualProjecting;
const q = view.debugElement.children[0].references!['q'] as ManualProjecting;
expect(q.query.length).toBe(0);
const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'});
@ -694,7 +695,7 @@ describe('Query API', () => {
</ng-template>
</manual-projecting>`;
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'] as ManualProjecting;
const q = view.debugElement.children[0].references!['q'] as ManualProjecting;
expect(q.query.length).toBe(0);
const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'});
@ -729,7 +730,7 @@ describe('Query API', () => {
</div>
`;
const view = createTestCmp(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
view.componentInstance.shouldShow = true;
view.detectChanges();
@ -751,13 +752,11 @@ describe('Query API', () => {
class AutoProjecting {
// TODO(issue/24571):
// remove '!'.
@ContentChild(TemplateRef)
content !: TemplateRef<any>;
@ContentChild(TemplateRef) content!: TemplateRef<any>;
// TODO(issue/24571):
// remove '!'.
@ContentChildren(TextDirective)
query !: QueryList<TextDirective>;
@ContentChildren(TextDirective) query!: QueryList<TextDirective>;
}
TestBed.configureTestingModule({declarations: [AutoProjecting]});
@ -765,7 +764,7 @@ describe('Query API', () => {
'<auto-projecting #q><ng-template><div text="1"></div></ng-template></auto-projecting>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
// This should be 1, but due to
// https://github.com/angular/angular/issues/15117
// this is 0.
@ -783,13 +782,11 @@ describe('Query API', () => {
class AutoProjecting {
// TODO(issue/24571):
// remove '!'.
@ContentChild(TemplateRef)
content !: TemplateRef<any>;
@ContentChild(TemplateRef) content!: TemplateRef<any>;
// TODO(issue/24571):
// remove '!'.
@ContentChildren(TextDirective)
query !: QueryList<TextDirective>;
@ContentChildren(TextDirective) query!: QueryList<TextDirective>;
}
TestBed.configureTestingModule({declarations: [AutoProjecting]});
@ -797,7 +794,7 @@ describe('Query API', () => {
'<auto-projecting #q><ng-template><div text="1"></div></ng-template></auto-projecting>';
const view = createTestCmpAndDetectChanges(MyComp0, template);
const q = view.debugElement.children[0].references !['q'];
const q = view.debugElement.children[0].references!['q'];
expect(q.query.length).toBe(1);
});
}
@ -808,35 +805,39 @@ describe('Query API', () => {
@Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'})
class TextDirective {
// TODO(issue/24571): remove '!'.
text !: string;
text!: string;
constructor() {}
}
@Component({selector: 'needs-content-children', template: ''})
class NeedsContentChildren implements AfterContentInit {
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective) textDirChildren !: QueryList<TextDirective>;
@ContentChildren(TextDirective) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
numberOfChildrenAfterContentInit !: number;
numberOfChildrenAfterContentInit!: number;
ngAfterContentInit() { this.numberOfChildrenAfterContentInit = this.textDirChildren.length; }
ngAfterContentInit() {
this.numberOfChildrenAfterContentInit = this.textDirChildren.length;
}
}
@Component({selector: 'needs-view-children', template: '<div text></div>'})
class NeedsViewChildren implements AfterViewInit {
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) textDirChildren !: QueryList<TextDirective>;
@ViewChildren(TextDirective) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
numberOfChildrenAfterViewInit !: number;
numberOfChildrenAfterViewInit!: number;
ngAfterViewInit() { this.numberOfChildrenAfterViewInit = this.textDirChildren.length; }
ngAfterViewInit() {
this.numberOfChildrenAfterViewInit = this.textDirChildren.length;
}
}
@Component({selector: 'needs-content-child', template: ''})
class NeedsContentChild implements AfterContentInit, AfterContentChecked {
/** @internal */
// TODO(issue/24571): remove '!'.
_child !: TextDirective;
_child!: TextDirective;
@ContentChild(TextDirective)
set child(value) {
@ -844,18 +845,24 @@ class NeedsContentChild implements AfterContentInit, AfterContentChecked {
this.logs.push(['setter', value ? value.text : null]);
}
get child() { return this._child; }
get child() {
return this._child;
}
logs: any[] /** TODO #9100 */ = [];
ngAfterContentInit() { this.logs.push(['init', this.child ? this.child.text : null]); }
ngAfterContentInit() {
this.logs.push(['init', this.child ? this.child.text : null]);
}
ngAfterContentChecked() { this.logs.push(['check', this.child ? this.child.text : null]); }
ngAfterContentChecked() {
this.logs.push(['check', this.child ? this.child.text : null]);
}
}
@Directive({selector: '[directive-needs-content-child]'})
class DirectiveNeedsContentChild {
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective) child !: TextDirective;
@ContentChild(TextDirective) child!: TextDirective;
}
@Component({selector: 'needs-view-child', template: `<div *ngIf="shouldShow" text="foo"></div>`})
@ -864,7 +871,7 @@ class NeedsViewChild implements AfterViewInit, AfterViewChecked {
shouldShow2: boolean = false;
/** @internal */
// TODO(issue/24571): remove '!'.
_child !: TextDirective;
_child!: TextDirective;
@ViewChild(TextDirective)
set child(value) {
@ -872,12 +879,18 @@ class NeedsViewChild implements AfterViewInit, AfterViewChecked {
this.logs.push(['setter', value ? value.text : null]);
}
get child() { return this._child; }
get child() {
return this._child;
}
logs: any[] /** TODO #9100 */ = [];
ngAfterViewInit() { this.logs.push(['init', this.child ? this.child.text : null]); }
ngAfterViewInit() {
this.logs.push(['init', this.child ? this.child.text : null]);
}
ngAfterViewChecked() { this.logs.push(['check', this.child ? this.child.text : null]); }
ngAfterViewChecked() {
this.logs.push(['check', this.child ? this.child.text : null]);
}
}
function createTestCmp<T>(type: Type<T>, template: string): ComponentFixture<T> {
@ -895,9 +908,9 @@ function createTestCmpAndDetectChanges<T>(type: Type<T>, template: string): Comp
@Component({selector: 'needs-static-content-view-child', template: `<div text="viewFoo"></div>`})
class NeedsStaticContentAndViewChild {
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective, {static: true}) contentChild !: TextDirective;
@ContentChild(TextDirective, {static: true}) contentChild!: TextDirective;
// TODO(issue/24571): remove '!'.
@ViewChild(TextDirective, {static: true}) viewChild !: TextDirective;
@ViewChild(TextDirective, {static: true}) viewChild!: TextDirective;
}
@Directive({selector: '[dir]'})
@ -910,19 +923,19 @@ class InertDirective {
})
class NeedsQuery {
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective) query !: QueryList<TextDirective>;
@ContentChildren(TextDirective) query!: QueryList<TextDirective>;
}
@Component({selector: 'needs-four-queries', template: ''})
class NeedsFourQueries {
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective) query1 !: TextDirective;
@ContentChild(TextDirective) query1!: TextDirective;
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective) query2 !: TextDirective;
@ContentChild(TextDirective) query2!: TextDirective;
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective) query3 !: TextDirective;
@ContentChild(TextDirective) query3!: TextDirective;
// TODO(issue/24571): remove '!'.
@ContentChild(TextDirective) query4 !: TextDirective;
@ContentChild(TextDirective) query4!: TextDirective;
}
@Component({
@ -931,25 +944,25 @@ class NeedsFourQueries {
})
class NeedsQueryDesc {
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective, {descendants: true}) query !: QueryList<TextDirective>;
@ContentChildren(TextDirective, {descendants: true}) query!: QueryList<TextDirective>;
}
@Component({selector: 'needs-query-by-ref-binding', template: '<ng-content>'})
class NeedsQueryByLabel {
// TODO(issue/24571): remove '!'.
@ContentChildren('textLabel', {descendants: true}) query !: QueryList<any>;
@ContentChildren('textLabel', {descendants: true}) query!: QueryList<any>;
}
@Component({selector: 'needs-view-query-by-ref-binding', template: '<div #textLabel>text</div>'})
class NeedsViewQueryByLabel {
// TODO(issue/24571): remove '!'.
@ViewChildren('textLabel') query !: QueryList<any>;
@ViewChildren('textLabel') query!: QueryList<any>;
}
@Component({selector: 'needs-query-by-ref-bindings', template: '<ng-content>'})
class NeedsQueryByTwoLabels {
// TODO(issue/24571): remove '!'.
@ContentChildren('textLabel1,textLabel2', {descendants: true}) query !: QueryList<any>;
@ContentChildren('textLabel1,textLabel2', {descendants: true}) query!: QueryList<any>;
}
@Component({
@ -958,7 +971,7 @@ class NeedsQueryByTwoLabels {
})
class NeedsQueryAndProject {
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective) query !: QueryList<TextDirective>;
@ContentChildren(TextDirective) query!: QueryList<TextDirective>;
}
@Component({
@ -967,14 +980,14 @@ class NeedsQueryAndProject {
})
class NeedsViewQuery {
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) query !: QueryList<TextDirective>;
@ViewChildren(TextDirective) query!: QueryList<TextDirective>;
}
@Component({selector: 'needs-view-query-if', template: '<div *ngIf="show" text="1"></div>'})
class NeedsViewQueryIf {
show: boolean = false;
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) query !: QueryList<TextDirective>;
@ViewChildren(TextDirective) query!: QueryList<TextDirective>;
}
@Component({
@ -984,7 +997,7 @@ class NeedsViewQueryIf {
class NeedsViewQueryNestedIf {
show: boolean = true;
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) query !: QueryList<TextDirective>;
@ViewChildren(TextDirective) query!: QueryList<TextDirective>;
}
@Component({
@ -995,7 +1008,7 @@ class NeedsViewQueryNestedIf {
})
class NeedsViewQueryOrder {
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) query !: QueryList<TextDirective>;
@ViewChildren(TextDirective) query!: QueryList<TextDirective>;
list: string[] = ['2', '3'];
}
@ -1007,16 +1020,16 @@ class NeedsViewQueryOrder {
})
class NeedsViewQueryOrderWithParent {
// TODO(issue/24571): remove '!'.
@ViewChildren(TextDirective) query !: QueryList<TextDirective>;
@ViewChildren(TextDirective) query!: QueryList<TextDirective>;
list: string[] = ['2', '3'];
}
@Component({selector: 'needs-tpl', template: '<ng-template><div>shadow</div></ng-template>'})
class NeedsTpl {
// TODO(issue/24571): remove '!'.
@ViewChildren(TemplateRef) viewQuery !: QueryList<TemplateRef<Object>>;
@ViewChildren(TemplateRef) viewQuery!: QueryList<TemplateRef<Object>>;
// TODO(issue/24571): remove '!'.
@ContentChildren(TemplateRef) query !: QueryList<TemplateRef<Object>>;
@ContentChildren(TemplateRef) query!: QueryList<TemplateRef<Object>>;
constructor(public vc: ViewContainerRef) {}
}
@ -1024,33 +1037,31 @@ class NeedsTpl {
{selector: 'needs-named-tpl', template: '<ng-template #tpl><div>shadow</div></ng-template>'})
class NeedsNamedTpl {
// TODO(issue/24571): remove '!'.
@ViewChild('tpl', {static: true}) viewTpl !: TemplateRef<Object>;
@ViewChild('tpl', {static: true}) viewTpl!: TemplateRef<Object>;
// TODO(issue/24571): remove '!'.
@ContentChild('tpl', {static: true}) contentTpl !: TemplateRef<Object>;
@ContentChild('tpl', {static: true}) contentTpl!: TemplateRef<Object>;
constructor(public vc: ViewContainerRef) {}
}
@Component({selector: 'needs-content-children-read', template: ''})
class NeedsContentChildrenWithRead {
// TODO(issue/24571): remove '!'.
@ContentChildren('q', {read: TextDirective}) textDirChildren !: QueryList<TextDirective>;
@ContentChildren('q', {read: TextDirective}) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
@ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar !: QueryList<TextDirective>;
@ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar!: QueryList<TextDirective>;
}
@Component({selector: 'needs-content-child-read', template: ''})
class NeedsContentChildWithRead {
// TODO(issue/24571): remove '!'.
@ContentChild('q', {read: TextDirective}) textDirChild !: TextDirective;
@ContentChild('q', {read: TextDirective}) textDirChild!: TextDirective;
// TODO(issue/24571): remove '!'.
@ContentChild('nonExisting', {read: TextDirective})
nonExistingVar !: TextDirective;
@ContentChild('nonExisting', {read: TextDirective}) nonExistingVar!: TextDirective;
}
@Component({selector: 'needs-content-children-shallow', template: ''})
class NeedsContentChildrenShallow {
@ContentChildren('q', {descendants: false})
children !: QueryList<ElementRef>;
@ContentChildren('q', {descendants: false}) children!: QueryList<ElementRef>;
}
@Component({
@ -1059,7 +1070,7 @@ class NeedsContentChildrenShallow {
})
class NeedsContentChildTemplateRef {
// TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true}) templateRef !: TemplateRef<any>;
@ContentChild(TemplateRef, {static: true}) templateRef!: TemplateRef<any>;
}
@Component({
@ -1077,9 +1088,9 @@ class NeedsContentChildTemplateRefApp {
})
class NeedsViewChildrenWithRead {
// TODO(issue/24571): remove '!'.
@ViewChildren('q,w', {read: TextDirective}) textDirChildren !: QueryList<TextDirective>;
@ViewChildren('q,w', {read: TextDirective}) textDirChildren!: QueryList<TextDirective>;
// TODO(issue/24571): remove '!'.
@ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar !: QueryList<TextDirective>;
@ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar!: QueryList<TextDirective>;
}
@Component({
@ -1088,27 +1099,28 @@ class NeedsViewChildrenWithRead {
})
class NeedsViewChildWithRead {
// TODO(issue/24571): remove '!'.
@ViewChild('q', {read: TextDirective}) textDirChild !: TextDirective;
@ViewChild('q', {read: TextDirective}) textDirChild!: TextDirective;
// TODO(issue/24571): remove '!'.
@ViewChild('nonExisting', {read: TextDirective}) nonExistingVar !: TextDirective;
@ViewChild('nonExisting', {read: TextDirective}) nonExistingVar!: TextDirective;
}
@Component({selector: 'needs-viewcontainer-read', template: '<div #q></div>'})
class NeedsViewContainerWithRead {
// TODO(issue/24571): remove '!'.
@ViewChild('q', {read: ViewContainerRef}) vc !: ViewContainerRef;
@ViewChild('q', {read: ViewContainerRef}) vc!: ViewContainerRef;
// TODO(issue/24571): remove '!'.
@ViewChild('nonExisting', {read: ViewContainerRef})
nonExistingVar !: ViewContainerRef;
@ViewChild('nonExisting', {read: ViewContainerRef}) nonExistingVar!: ViewContainerRef;
// TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true}) template !: TemplateRef<Object>;
createView() { this.vc.createEmbeddedView(this.template); }
createView() {
this.vc.createEmbeddedView(this.template);
}
}
@Component({selector: 'has-null-query-condition', template: '<div></div>'})
class HasNullQueryCondition {
@ContentChildren(null !) errorTrigger: any;
@ContentChildren(null!) errorTrigger: any;
}
@Component({selector: 'my-comp', template: ''})
@ -1127,14 +1139,16 @@ class ManualProjecting {
@ContentChild(TemplateRef, {static: true}) template !: TemplateRef<any>;
// TODO(issue/24571): remove '!'.
@ViewChild('vc', {read: ViewContainerRef})
vc !: ViewContainerRef;
@ViewChild('vc', {read: ViewContainerRef}) vc!: ViewContainerRef;
// TODO(issue/24571): remove '!'.
@ContentChildren(TextDirective)
query !: QueryList<TextDirective>;
@ContentChildren(TextDirective) query!: QueryList<TextDirective>;
create() { this.vc.createEmbeddedView(this.template); }
create() {
this.vc.createEmbeddedView(this.template);
}
destroy() { this.vc.clear(); }
destroy() {
this.vc.clear();
}
}

View File

@ -21,10 +21,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
log = '';
});
function logAppend(item: any /** TODO #9100 */) { log += (log.length == 0 ? '' : ', ') + item; }
function logAppend(item: any /** TODO #9100 */) {
log += (log.length == 0 ? '' : ', ') + item;
}
describe('dirty and reset', () => {
it('should initially be dirty and empty', () => {
expect(queryList.dirty).toBeTruthy();
expect(queryList.length).toBe(0);
@ -36,7 +37,6 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
expect(queryList.dirty).toBeFalsy();
expect(queryList.length).toBe(2);
});
});
it('should support resetting and iterating over the new objects', () => {
@ -146,7 +146,7 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
// For loops use the iteration protocol.
for (const value of queryListAsIterable) {
expect(value).toBe(data.shift() !);
expect(value).toBe(data.shift()!);
}
expect(data.length).toBe(0);
});
@ -155,7 +155,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
describe('simple observable interface', () => {
it('should fire callbacks on change', fakeAsync(() => {
let fires = 0;
queryList.changes.subscribe({next: (_) => { fires += 1; }});
queryList.changes.subscribe({
next: (_) => {
fires += 1;
}
});
queryList.notifyOnChanges();
tick();
@ -170,7 +174,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
it('should provides query list as an argument', fakeAsync(() => {
let recorded: any /** TODO #9100 */;
queryList.changes.subscribe({next: (v: any) => { recorded = v; }});
queryList.changes.subscribe({
next: (v: any) => {
recorded = v;
}
});
queryList.reset(['one']);
queryList.notifyOnChanges();

View File

@ -7,18 +7,24 @@
*/
import {DOCUMENT, ɵgetDOM as getDOM} from '@angular/common';
import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, destroyPlatform, ɵivyEnabled as ivyEnabled} from '@angular/core';
import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing';
import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, destroyPlatform, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵivyEnabled as ivyEnabled} from '@angular/core';
import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {BrowserModule, By} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {modifiedInIvy, onlyInIvy} from '@angular/private/testing';
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
declareTestsUsingBootstrap();
@ -26,11 +32,14 @@ declareTestsUsingBootstrap();
function declareTests(config?: {useJit: boolean}) {
// Place to put reproductions for regressions
describe('regressions', () => {
beforeEach(() => { TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]}); });
beforeEach(() => {
TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]});
});
describe('platform pipes', () => {
beforeEach(() => { TestBed.configureCompiler({...config}); });
beforeEach(() => {
TestBed.configureCompiler({...config});
});
it('should overwrite them by custom pipes', () => {
TestBed.configureTestingModule({declarations: [CustomPipe]});
@ -84,14 +93,20 @@ function declareTests(config?: {useJit: boolean}) {
class MyDir {
setterCalls: {[key: string]: any} = {};
// TODO(issue/24571): remove '!'.
changes !: SimpleChanges;
changes!: SimpleChanges;
@Input()
set a(v: number) { this.setterCalls['a'] = v; }
set a(v: number) {
this.setterCalls['a'] = v;
}
@Input()
set b(v: number) { this.setterCalls['b'] = v; }
set b(v: number) {
this.setterCalls['b'] = v;
}
ngOnChanges(changes: SimpleChanges) { this.changes = changes; }
ngOnChanges(changes: SimpleChanges) {
this.changes = changes;
}
}
TestBed.configureTestingModule({declarations: [MyDir, MyComp]});
@ -128,7 +143,7 @@ function declareTests(config?: {useJit: boolean}) {
@Component({selector: 'some-comp', template: '<p (click)="nullValue?.click()"></p>'})
class SomeComponent {
// TODO(issue/24571): remove '!'.
nullValue !: SomeReferencedClass;
nullValue!: SomeReferencedClass;
}
class SomeReferencedClass {
@ -195,20 +210,17 @@ function declareTests(config?: {useJit: boolean}) {
});
describe('ANALYZE_FOR_ENTRY_COMPONENTS providers', () => {
it('should support class instances', () => {
class SomeObject {
someMethod() {}
}
expect(
() => createInjector([
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: new SomeObject(), multi: true}
]))
expect(() => createInjector([
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: new SomeObject(), multi: true}
]))
.not.toThrow();
});
});
});
it('should allow logging a previous elements class binding via interpolation', () => {
@ -298,8 +310,7 @@ function declareTests(config?: {useJit: boolean}) {
@Component({template: '<div #vc></div><div *ngIf="show" #vc></div>'})
class MyComp {
// TODO(issue/24571): remove '!'.
@ViewChildren('vc', {read: ViewContainerRef})
viewContainers !: QueryList<ViewContainerRef>;
@ViewChildren('vc', {read: ViewContainerRef}) viewContainers!: QueryList<ViewContainerRef>;
show = true;
}
@ -361,7 +372,7 @@ function declareTests(config?: {useJit: boolean}) {
@Directive({selector: 'test'})
class Test {
// TODO(issue/24571): remove '!'.
@Input() @ContentChild(TemplateRef, {static: true}) tpl !: TemplateRef<any>;
@Input() @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
}
@Component({
@ -391,7 +402,7 @@ function declareTests(config?: {useJit: boolean}) {
.it('should throw if @ContentChild and @Input are on the same property', () => {
@Directive({selector: 'test'})
class Test {
@Input() @ContentChild(TemplateRef, {static: true}) tpl !: TemplateRef<any>;
@Input() @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
}
@Component({selector: 'my-app', template: `<test></test>`})
@ -412,8 +423,8 @@ function declareTests(config?: {useJit: boolean}) {
class MyModule {
}
const modRef = TestBed.configureTestingModule({imports: [MyModule]})
.get(NgModuleRef) as NgModuleRef<MyModule>;
const modRef = TestBed.configureTestingModule({imports: [MyModule]}).get(NgModuleRef) as
NgModuleRef<MyModule>;
const compRef =
modRef.componentFactoryResolver.resolveComponentFactory(App).create(Injector.NULL);
@ -429,7 +440,9 @@ function declareTestsUsingBootstrap() {
class MockConsole {
errors: any[][] = [];
error(...s: any[]): void { this.errors.push(s); }
error(...s: any[]): void {
this.errors.push(s);
}
}
let logger: MockConsole;
@ -445,7 +458,9 @@ function declareTestsUsingBootstrap() {
(errorHandler as any)._console = logger as any;
}));
afterEach(() => { destroyPlatform(); });
afterEach(() => {
destroyPlatform();
});
if (getDOM().supportsDOMEvents()) {
// This test needs a real DOM....
@ -459,7 +474,9 @@ function declareTestsUsingBootstrap() {
class ErrorComp {
value = 0;
thrownValue = 0;
next() { this.value++; }
next() {
this.value++;
}
nextAndThrow() {
this.value++;
this.throwIfNeeded();
@ -475,11 +492,12 @@ function declareTestsUsingBootstrap() {
@Directive({selector: '[dirClick]'})
class EventDir {
@Output()
dirClick = new EventEmitter();
@Output() dirClick = new EventEmitter();
@HostListener('click', ['$event'])
onClick(event: any) { this.dirClick.next(event); }
onClick(event: any) {
this.dirClick.next(event);
}
}
@NgModule({
@ -552,12 +570,16 @@ class MyComp1 {
@Pipe({name: 'somePipe', pure: true})
class PlatformPipe implements PipeTransform {
transform(value: any): any { return 'somePlatformPipe'; }
transform(value: any): any {
return 'somePlatformPipe';
}
}
@Pipe({name: 'somePipe', pure: true})
class CustomPipe implements PipeTransform {
transform(value: any): any { return 'someCustomPipe'; }
transform(value: any): any {
return 'someCustomPipe';
}
}
@Component({selector: 'cmp-content', template: `<ng-content></ng-content>`})
@ -571,7 +593,9 @@ class MyCountingComp {
return {value: 'counting method value'};
}
static reset() { MyCountingComp.calls = 0; }
static reset() {
MyCountingComp.calls = 0;
}
static calls = 0;
}
@ -581,7 +605,9 @@ class CountingPipe implements PipeTransform {
CountingPipe.calls++;
return {value: 'counting pipe value'};
}
static reset() { CountingPipe.calls = 0; }
static reset() {
CountingPipe.calls = 0;
}
static calls = 0;
}

View File

@ -8,16 +8,22 @@
import {ɵgetDOM as getDOM} from '@angular/common';
import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA, ɵivyEnabled as ivyEnabled} from '@angular/core';
import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing';
import {ComponentFixture, getTestBed, TestBed} from '@angular/core/testing';
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';
import {modifiedInIvy, onlyInIvy} from '@angular/private/testing';
{
if (ivyEnabled) {
describe('ivy', () => { declareTests(); });
describe('ivy', () => {
declareTests();
});
} else {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
describe('jit', () => {
declareTests({useJit: true});
});
describe('no jit', () => {
declareTests({useJit: false});
});
}
}
@ -34,7 +40,6 @@ class OnPrefixDir {
function declareTests(config?: {useJit: boolean}) {
describe('security integration tests', function() {
beforeEach(() => {
TestBed.configureCompiler({...config}).configureTestingModule({
declarations: [
@ -49,7 +54,9 @@ function declareTests(config?: {useJit: boolean}) {
originalLog = getDOM().log;
getDOM().log = (msg) => { /* disable logging */ };
});
afterEach(() => { getDOM().log = originalLog; });
afterEach(() => {
getDOM().log = originalLog;
});
describe('events', () => {
modifiedInIvy('on-prefixed attributes validation happens at runtime in Ivy')
@ -113,7 +120,7 @@ function declareTests(config?: {useJit: boolean}) {
});
// should not throw for inputs starting with "on"
let cmp: ComponentFixture<SecuredComponent> = undefined !;
let cmp: ComponentFixture<SecuredComponent> = undefined!;
expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow();
// must bind to the directive not to the property of the div
@ -124,7 +131,6 @@ function declareTests(config?: {useJit: boolean}) {
expect(getDOM().getProperty(div.nativeElement, 'onclick')).not.toBe(value);
expect(div.nativeElement.hasAttribute('onclick')).toEqual(false);
});
});
describe('safe HTML values', function() {
@ -206,8 +212,7 @@ function declareTests(config?: {useJit: boolean}) {
@Directive({selector: '[dirHref]'})
class HrefDirective {
// TODO(issue/24571): remove '!'.
@HostBinding('href') @Input()
dirHref !: string;
@HostBinding('href') @Input() dirHref!: string;
}
const template = `<a [dirHref]="ctxProp">Link Title</a>`;
@ -222,8 +227,7 @@ function declareTests(config?: {useJit: boolean}) {
@Directive({selector: '[dirHref]'})
class HrefDirective {
// TODO(issue/24571): remove '!'.
@HostBinding('attr.href') @Input()
dirHref !: string;
@HostBinding('attr.href') @Input() dirHref!: string;
}
const template = `<a [dirHref]="ctxProp">Link Title</a>`;

View File

@ -16,7 +16,7 @@ import {Attribute, Component, Directive, ErrorHandler, ɵglobal} from '@angular/
import {CompilerFacade, ExportedCompilerFacade} from '@angular/core/src/compiler/compiler_facade';
import {getErrorLogger} from '@angular/core/src/errors';
import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading';
import {TestBed, fakeAsync, tick} from '@angular/core/testing';
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
import {modifiedInIvy, onlyInIvy} from '@angular/private/testing';
describe('jit source mapping', () => {
@ -44,7 +44,9 @@ describe('jit source mapping', () => {
.describe('(View Engine)', () => {
describe('inline templates', () => {
const ngUrl = 'ng:///DynamicTestModule/MyComp.html';
function templateDecorator(template: string) { return {template}; }
function templateDecorator(template: string) {
return {template};
}
declareTests({ngUrl, templateDecorator});
});
@ -66,7 +68,9 @@ describe('jit source mapping', () => {
class MyComp {
}
expect(() => { compileAndCreateComponent(MyComp); })
expect(() => {
compileAndCreateComponent(MyComp);
})
.toThrowError(
new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:2`));
}));
@ -76,7 +80,9 @@ describe('jit source mapping', () => {
class MyComp {
}
expect(() => { compileAndCreateComponent(MyComp); })
expect(() => {
compileAndCreateComponent(MyComp);
})
.toThrowError(
new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`));
}));
@ -105,7 +111,9 @@ describe('jit source mapping', () => {
@Directive({selector: '[someDir]'})
class SomeDir {
constructor() { throw new Error('Test'); }
constructor() {
throw new Error('Test');
}
}
TestBed.configureTestingModule({declarations: [SomeDir]});
@ -163,7 +171,9 @@ describe('jit source mapping', () => {
@Component({...templateDecorator(template)})
class MyComp {
createError() { throw new Error('Test'); }
createError() {
throw new Error('Test');
}
}
const comp = compileAndCreateComponent(MyComp);
@ -195,7 +205,9 @@ describe('jit source mapping', () => {
@Component({...templateDecorator(template)})
class MyComp {
createError() { throw new Error('Test'); }
createError() {
throw new Error('Test');
}
}
const comp = compileAndCreateComponent(MyComp);
@ -219,19 +231,19 @@ describe('jit source mapping', () => {
column: 4,
source: ngUrl,
});
}));
}
});
onlyInIvy('Generated filenames and stack traces have changed in ivy').describe('(Ivy)', () => {
beforeEach(() => overrideCompilerFacade());
afterEach(() => restoreCompilerFacade());
describe('inline templates', () => {
const ngUrl = 'ng:///MyComp/template.html';
function templateDecorator(template: string) { return {template}; }
function templateDecorator(template: string) {
return {template};
}
declareTests({ngUrl, templateDecorator});
});
@ -268,7 +280,9 @@ describe('jit source mapping', () => {
class MyComp {
}
expect(() => { resolveCompileAndCreateComponent(MyComp, template); })
expect(() => {
resolveCompileAndCreateComponent(MyComp, template);
})
.toThrowError(
new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`));
}));
@ -297,7 +311,9 @@ describe('jit source mapping', () => {
@Directive({selector: '[someDir]'})
class SomeDir {
constructor() { throw new Error('Test'); }
constructor() {
throw new Error('Test');
}
}
TestBed.configureTestingModule({declarations: [SomeDir]});
@ -351,7 +367,9 @@ describe('jit source mapping', () => {
@Component({...templateDecorator(template)})
class MyComp {
createError() { throw new Error('Test'); }
createError() {
throw new Error('Test');
}
}
const comp = resolveCompileAndCreateComponent(MyComp, template);
@ -375,7 +393,9 @@ describe('jit source mapping', () => {
@Component({...templateDecorator(template)})
class MyComp {
createError() { throw new Error('Test'); }
createError() {
throw new Error('Test');
}
}
const comp = resolveCompileAndCreateComponent(MyComp, template);
@ -414,7 +434,9 @@ describe('jit source mapping', () => {
return TestBed.createComponent(comType);
}
function createResolver(contents: string) { return (_url: string) => Promise.resolve(contents); }
function createResolver(contents: string) {
return (_url: string) => Promise.resolve(contents);
}
function resolveCompileAndCreateComponent(comType: any, template: string) {
resolveComponentResources(createResolver(template));
@ -438,7 +460,9 @@ describe('jit source mapping', () => {
interface TestConfig {
ngUrl: string;
templateDecorator: (template: string) => { [key: string]: any };
templateDecorator: (template: string) => {
[key: string]: any
};
}
interface SourcePos {
@ -448,8 +472,8 @@ describe('jit source mapping', () => {
}
/**
* A helper class that captures the sources that have been JIT compiled.
*/
* A helper class that captures the sources that have been JIT compiled.
*/
class MockJitEvaluator extends JitEvaluator {
sources: string[] = [];
@ -466,7 +490,7 @@ describe('jit source mapping', () => {
*/
getSourceMap(genFile: string): SourceMap {
return this.sources.map(source => extractSourceMap(source))
.find(map => !!(map && map.file === genFile)) !;
.find(map => !!(map && map.file === genFile))!;
}
getSourcePositionForStack(stack: string, genFile: string): SourcePos {
@ -475,9 +499,9 @@ describe('jit source mapping', () => {
.map(line => urlRegexp.exec(line))
.filter(match => !!match)
.map(match => ({
file: match ![1],
line: parseInt(match ![2], 10),
column: parseInt(match ![3], 10)
file: match![1],
line: parseInt(match![2], 10),
column: parseInt(match![3], 10)
}))
.shift();
if (!pos) {
@ -489,8 +513,8 @@ describe('jit source mapping', () => {
}
function getErrorLoggerStack(e: Error): string {
let logStack: string = undefined !;
getErrorLogger(e)(<any>{error: () => logStack = new Error().stack !}, e.message);
let logStack: string = undefined!;
getErrorLogger(e)(<any>{error: () => logStack = new Error().stack!}, e.message);
return logStack;
}
});

View File

@ -32,12 +32,15 @@ describe('SystemJsNgModuleLoader', () => {
'prefixed/test/suffixed': {'NamedNgFactory': 'test module factory'}
});
});
afterEach(() => { global['System'] = oldSystem; });
afterEach(() => {
global['System'] = oldSystem;
});
it('loads a default factory by appending the factory suffix', async(() => {
const loader = new SystemJsNgModuleLoader(new Compiler());
loader.load('test').then(
contents => { expect(contents).toBe('test module factory' as any); });
loader.load('test').then(contents => {
expect(contents).toBe('test module factory' as any);
});
}));
it('loads a named factory by appending the factory suffix', async(() => {
const loader = new SystemJsNgModuleLoader(new Compiler());
@ -63,12 +66,15 @@ describe('SystemJsNgModuleLoader', () => {
'test': {'default': 'test module', 'NamedModule': 'test NamedModule'},
});
});
afterEach(() => { global['System'] = oldSystem; });
afterEach(() => {
global['System'] = oldSystem;
});
it('loads a default module', async(() => {
const loader = new SystemJsNgModuleLoader(new Compiler());
loader.load('test').then(
contents => { expect(contents.moduleType).toBe('test module' as any); });
loader.load('test').then(contents => {
expect(contents.moduleType).toBe('test module' as any);
});
}));
it('loads a named module', async(() => {
const loader = new SystemJsNgModuleLoader(new Compiler());

View File

@ -7,7 +7,7 @@
*/
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, DebugElement, Directive, ElementRef, EmbeddedViewRef, Host, Inject, InjectionToken, Injector, Input, NgModule, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing';
@ -32,61 +32,81 @@ class CycleDirective {
@Directive({selector: '[needsDirectiveFromSelf]'})
class NeedsDirectiveFromSelf {
dependency: SimpleDirective;
constructor(@Self() dependency: SimpleDirective) { this.dependency = dependency; }
constructor(@Self() dependency: SimpleDirective) {
this.dependency = dependency;
}
}
@Directive({selector: '[optionallyNeedsDirective]'})
class OptionallyNeedsDirective {
dependency: SimpleDirective;
constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; }
constructor(@Self() @Optional() dependency: SimpleDirective) {
this.dependency = dependency;
}
}
@Directive({selector: '[needsComponentFromHost]'})
class NeedsComponentFromHost {
dependency: SimpleComponent;
constructor(@Host() dependency: SimpleComponent) { this.dependency = dependency; }
constructor(@Host() dependency: SimpleComponent) {
this.dependency = dependency;
}
}
@Directive({selector: '[needsDirectiveFromHost]'})
class NeedsDirectiveFromHost {
dependency: SimpleDirective;
constructor(@Host() dependency: SimpleDirective) { this.dependency = dependency; }
constructor(@Host() dependency: SimpleDirective) {
this.dependency = dependency;
}
}
@Directive({selector: '[needsDirective]'})
class NeedsDirective {
dependency: SimpleDirective;
constructor(dependency: SimpleDirective) { this.dependency = dependency; }
constructor(dependency: SimpleDirective) {
this.dependency = dependency;
}
}
@Directive({selector: '[needsService]'})
class NeedsService {
service: any;
constructor(@Inject('service') service: any) { this.service = service; }
constructor(@Inject('service') service: any) {
this.service = service;
}
}
@Directive({selector: '[needsAppService]'})
class NeedsAppService {
service: any;
constructor(@Inject('appService') service: any) { this.service = service; }
constructor(@Inject('appService') service: any) {
this.service = service;
}
}
@Component({selector: '[needsHostAppService]', template: ''})
class NeedsHostAppService {
service: any;
constructor(@Host() @Inject('appService') service: any) { this.service = service; }
constructor(@Host() @Inject('appService') service: any) {
this.service = service;
}
}
@Component({selector: '[needsServiceComponent]', template: ''})
class NeedsServiceComponent {
service: any;
constructor(@Inject('service') service: any) { this.service = service; }
constructor(@Inject('service') service: any) {
this.service = service;
}
}
@Directive({selector: '[needsServiceFromHost]'})
class NeedsServiceFromHost {
service: any;
constructor(@Host() @Inject('service') service: any) { this.service = service; }
constructor(@Host() @Inject('service') service: any) {
this.service = service;
}
}
@Directive({selector: '[needsAttribute]'})
@ -146,36 +166,50 @@ class PushComponentNeedsChangeDetectorRef {
@Pipe({name: 'purePipe', pure: true})
class PurePipe implements PipeTransform {
constructor() {}
transform(value: any): any { return this; }
transform(value: any): any {
return this;
}
}
@Pipe({name: 'impurePipe', pure: false})
class ImpurePipe implements PipeTransform {
constructor() {}
transform(value: any): any { return this; }
transform(value: any): any {
return this;
}
}
@Pipe({name: 'pipeNeedsChangeDetectorRef'})
class PipeNeedsChangeDetectorRef {
constructor(public changeDetectorRef: ChangeDetectorRef) {}
transform(value: any): any { return this; }
transform(value: any): any {
return this;
}
}
@Pipe({name: 'pipeNeedsService'})
export class PipeNeedsService implements PipeTransform {
service: any;
constructor(@Inject('service') service: any) { this.service = service; }
transform(value: any): any { return this; }
constructor(@Inject('service') service: any) {
this.service = service;
}
transform(value: any): any {
return this;
}
}
@Pipe({name: 'duplicatePipe'})
export class DuplicatePipe1 implements PipeTransform {
transform(value: any): any { return this; }
transform(value: any): any {
return this;
}
}
@Pipe({name: 'duplicatePipe'})
export class DuplicatePipe2 implements PipeTransform {
transform(value: any): any { return this; }
transform(value: any): any {
return this;
}
}
@Component({selector: 'root', template: ''})
@ -183,15 +217,15 @@ class TestComp {
}
function createComponentFixture<T>(
template: string, providers?: Provider[] | null, comp?: Type<T>): ComponentFixture<T> {
template: string, providers?: Provider[]|null, comp?: Type<T>): ComponentFixture<T> {
if (!comp) {
comp = <any>TestComp;
}
TestBed.overrideComponent(comp !, {set: {template}});
TestBed.overrideComponent(comp!, {set: {template}});
if (providers && providers.length) {
TestBed.overrideComponent(comp !, {add: {providers: providers}});
TestBed.overrideComponent(comp!, {add: {providers: providers}});
}
return TestBed.createComponent(comp !);
return TestBed.createComponent(comp!);
}
function createComponent(template: string, providers?: Provider[], comp?: Type<any>): DebugElement {
@ -351,7 +385,6 @@ describe('View injector', () => {
});
describe('injecting lazy providers into an eager provider via Injector.get', () => {
it('should inject providers that were declared before it', () => {
@Component({
template: '',
@ -448,7 +481,9 @@ describe('View injector', () => {
@Component({providers: [{provide: 'a', useFactory: () => 'aValue'}], template: ''})
class SomeComponent {
public a: string;
constructor(injector: Injector) { this.a = injector.get('a'); }
constructor(injector: Injector) {
this.a = injector.get('a');
}
}
const comp = TestBed.configureTestingModule({declarations: [SomeComponent]})
@ -461,8 +496,12 @@ describe('View injector', () => {
let destroyed = false;
class SomeInjectable {
constructor() { created = true; }
ngOnDestroy() { destroyed = true; }
constructor() {
created = true;
}
ngOnDestroy() {
destroyed = true;
}
}
@Component({providers: [SomeInjectable], template: ''})
@ -910,7 +949,7 @@ describe('View injector', () => {
const testInjector = <Injector>{
get: (token: any, notFoundValue: any) =>
token === 'someToken' ? 'someNewValue' : notFoundValue
token === 'someToken' ? 'someNewValue' : notFoundValue
};
const compFactory = TestBed.configureTestingModule({imports: [TestModule]})
@ -961,8 +1000,7 @@ describe('View injector', () => {
it('should inject ChangeDetectorRef into pipes', () => {
TestBed.configureTestingModule({
declarations:
[SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
declarations: [SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
});
const el = createComponent(
'<div [simpleDirective]="true | pipeNeedsChangeDetectorRef" directiveNeedsChangeDetectorRef></div>');