refactor(core): Removed linker test references to TestComponentBuilder (#10903)

Removed references to TestComponentBuilder from:
  query_integration_spec.ts
  regression_integration_spec.ts
  security_integration_spec.ts
  view_injector_integration_spec.ts
This commit is contained in:
Chuck Jazdzewski 2016-08-17 16:52:39 -07:00 committed by Kara
parent c48021ab97
commit a5c0349d88
4 changed files with 1128 additions and 1454 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ import {NgClass, NgIf} from '@angular/common';
import {Component, Injector, OpaqueToken, Pipe, PipeTransform, forwardRef} from '@angular/core';
import {ViewMetadata} from '@angular/core/src/metadata/view';
import {TestBed} from '@angular/core/testing';
import {AsyncTestCompleter, TestComponentBuilder, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
@ -23,199 +23,134 @@ function declareTests({useJit}: {useJit: boolean}) {
// Place to put reproductions for regressions
describe('regressions', () => {
describe('platform pipes', () => {
beforeEach(() => {
TestBed.configureCompiler({useJit: useJit});
TestBed.configureTestingModule({declarations: [PlatformPipe]});
});
beforeEach(() => { TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]}); });
describe('platform pipes', () => {
beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });
it('should overwrite them by custom pipes', () => {
TestBed.configureTestingModule({declarations: [CustomPipe]});
const template = '{{true | somePipe}}';
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
it('should overwrite them by custom pipes',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideView(
MyComp1,
new ViewMetadata({template: '{{true | somePipe}}', pipes: [CustomPipe]}))
.createAsync(MyComp1)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('someCustomPipe');
async.done();
});
}));
});
describe('expressions', () => {
it('should evaluate conditional and boolean operators with right precedence - #8244', () => {
const template = `{{'red' + (true ? ' border' : '')}}`;
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
it('should evaluate conditional and boolean operators with right precedence - #8244',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideView(
MyComp1, new ViewMetadata({template: `{{'red' + (true ? ' border' : '')}}`}))
.createAsync(MyComp1)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('red border');
async.done();
});
}));
it('should evaluate conditional and unary operators with right precedence - #8235',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideView(MyComp1, new ViewMetadata({template: `{{!null?.length}}`}))
.createAsync(MyComp1)
.then((fixture) => {
it('should evaluate conditional and unary operators with right precedence - #8235', () => {
const template = `{{!null?.length}}`;
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('true');
async.done();
});
}));
it('should only evaluate stateful pipes once - #10639',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideView(
MyComp1,
new ViewMetadata(
{template: '{{(null|countingPipe)?.value}}', pipes: [CountingPipe]}))
.createAsync(MyComp1)
.then(fixture => {
it('should only evaluate stateful pipes once - #10639', () => {
TestBed.configureTestingModule({declarations: [CountingPipe]});
const template = '{{(null|countingPipe)?.value}}';
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
CountingPipe.reset();
fixture.detectChanges(/* checkNoChanges */ false);
expect(fixture.nativeElement).toHaveText('counting pipe value');
expect(CountingPipe.calls).toBe(1);
async.done();
});
}));
it('should only evaluate methods once - #10639',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideView(MyCountingComp, new ViewMetadata({template: '{{method()?.value}}'}))
.createAsync(MyCountingComp)
.then(fixture => {
it('should only evaluate methods once - #10639', () => {
TestBed.configureTestingModule({declarations: [MyCountingComp]});
const template = '{{method()?.value}}';
TestBed.overrideComponent(MyCountingComp, {set: {template}});
const fixture = TestBed.createComponent(MyCountingComp);
MyCountingComp.reset();
fixture.detectChanges(/* checkNoChanges */ false);
expect(fixture.nativeElement).toHaveText('counting method value');
expect(MyCountingComp.calls).toBe(1);
async.done();
});
}));
});
describe('providers', () => {
function createInjector(tcb: TestComponentBuilder, proviers: any[]): Promise<Injector> {
return tcb.overrideProviders(MyComp1, [proviers])
.createAsync(MyComp1)
.then((fixture) => fixture.componentInstance.injector);
function createInjector(providers: any[]): Injector {
TestBed.overrideComponent(MyComp1, {add: {providers}});
return TestBed.createComponent(MyComp1).componentInstance.injector;
}
it('should support providers with an OpaqueToken that contains a `.` in the name',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
it('should support providers with an OpaqueToken that contains a `.` in the name', () => {
var token = new OpaqueToken('a.b');
var tokenValue = 1;
createInjector(tcb, [
{provide: token, useValue: tokenValue}
]).then((injector: Injector) => {
const injector = createInjector([{provide: token, useValue: tokenValue}]);
expect(injector.get(token)).toEqual(tokenValue);
async.done();
});
}));
it('should support providers with string token with a `.` in it',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
it('should support providers with string token with a `.` in it', () => {
var token = 'a.b';
var tokenValue = 1;
createInjector(tcb, [
{provide: token, useValue: tokenValue}
]).then((injector: Injector) => {
expect(injector.get(token)).toEqual(tokenValue);
async.done();
});
}));
const injector = createInjector([{provide: token, useValue: tokenValue}]);
it('should support providers with an anonymous function',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
expect(injector.get(token)).toEqual(tokenValue);
});
it('should support providers with an anonymous function', () => {
var token = () => true;
var tokenValue = 1;
createInjector(tcb, [
{provide: token, useValue: tokenValue}
]).then((injector: Injector) => {
expect(injector.get(token)).toEqual(tokenValue);
async.done();
});
}));
const injector = createInjector([{provide: token, useValue: tokenValue}]);
it('should support providers with an OpaqueToken that has a StringMap as value',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
expect(injector.get(token)).toEqual(tokenValue);
});
it('should support providers with an OpaqueToken that has a StringMap as value', () => {
var token1 = new OpaqueToken('someToken');
var token2 = new OpaqueToken('someToken');
var tokenValue1 = {'a': 1};
var tokenValue2 = {'a': 1};
createInjector(tcb, [
{provide: token1, useValue: tokenValue1},
{provide: token2, useValue: tokenValue2}
]).then((injector: Injector) => {
const injector = createInjector(
[{provide: token1, useValue: tokenValue1}, {provide: token2, useValue: tokenValue2}]);
expect(injector.get(token1)).toEqual(tokenValue1);
expect(injector.get(token2)).toEqual(tokenValue2);
async.done();
});
}));
});
it('should allow logging a previous elements class binding via interpolation',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideTemplate(
MyComp1, `<div [class.a]="true" #el>Class: {{el.className}}</div>`)
.createAsync(MyComp1)
.then((fixture) => {
it('should allow logging a previous elements class binding via interpolation', () => {
const template = `<div [class.a]="true" #el>Class: {{el.className}}</div>`;
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('Class: a');
async.done();
});
}));
it('should support ngClass before a component and content projection inside of an ngIf',
inject(
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
tcb.overrideView(
MyComp1, new ViewMetadata({
template: `A<cmp-content *ngIf="true" [ngClass]="'red'">B</cmp-content>C`,
directives: [NgClass, NgIf, CmpWithNgContent]
}))
.createAsync(MyComp1)
.then((fixture) => {
it('should support ngClass before a component and content projection inside of an ngIf', () => {
TestBed.configureTestingModule({declarations: [CmpWithNgContent]});
const template = `A<cmp-content *ngIf="true" [ngClass]="'red'">B</cmp-content>C`;
TestBed.overrideComponent(MyComp1, {set: {template}});
const fixture = TestBed.createComponent(MyComp1);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('ABC');
async.done();
});
}));
it('should handle mutual recursion entered from multiple sides - #7084',
inject(
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
tcb.createAsync(FakeRecursiveComp).then((fixture) => {
it('should handle mutual recursion entered from multiple sides - #7084', () => {
TestBed.configureTestingModule({declarations: [FakeRecursiveComp, LeftComp, RightComp]});
const fixture = TestBed.createComponent(FakeRecursiveComp);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('[]');
async.done();
});
}));
});
}
@ -262,10 +197,6 @@ class CountingPipe implements PipeTransform {
@Component({
selector: 'left',
template: `L<right *ngIf="false"></right>`,
directives: [
NgIf,
forwardRef(() => RightComp),
]
})
class LeftComp {
}
@ -273,10 +204,6 @@ class LeftComp {
@Component({
selector: 'right',
template: `R<left *ngIf="false"></left>`,
directives: [
NgIf,
forwardRef(() => LeftComp),
]
})
class RightComp {
}
@ -284,11 +211,6 @@ class RightComp {
@Component({
selector: 'fakeRecursiveComp',
template: `[<left *ngIf="false"></left><right *ngIf="false"></right>]`,
directives: [
NgIf,
forwardRef(() => LeftComp),
forwardRef(() => RightComp),
]
})
export class FakeRecursiveComp {
}

View File

@ -7,42 +7,30 @@
*/
import {Component} from '@angular/core/src/metadata';
import {TestBed} from '@angular/core/testing';
import {AsyncTestCompleter, TestComponentBuilder, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {TestBed, getTestBed} from '@angular/core/testing';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DomSanitizationService} from '@angular/platform-browser/src/security/dom_sanitization_service';
export function main() {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
@Component({selector: 'my-comp', template: '', directives: []})
@Component({selector: 'my-comp', template: ''})
class SecuredComponent {
ctxProp: string;
constructor() { this.ctxProp = 'some value'; }
}
function itAsync(msg: string, injections: Function[], f: Function): void;
function itAsync(
msg: string, f: (tcb: TestComponentBuilder, atc: AsyncTestCompleter) => void): void;
function itAsync(
msg: string, f: Function[] | ((tcb: TestComponentBuilder, atc: AsyncTestCompleter) => void),
fn?: Function): void {
if (f instanceof Function) {
it(msg, inject([TestComponentBuilder, AsyncTestCompleter], <Function>f));
} else {
let injections = f;
it(msg, inject(injections, fn));
}
}
function declareTests({useJit}: {useJit: boolean}) {
describe('security integration tests', function() {
beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });
beforeEach(() => {
TestBed.configureCompiler({useJit: useJit});
TestBed.configureTestingModule({declarations: [SecuredComponent]});
});
let originalLog: (msg: any) => any;
beforeEach(() => {
@ -52,91 +40,68 @@ function declareTests({useJit}: {useJit: boolean}) {
afterEach(() => { getDOM().log = originalLog; });
itAsync(
'should disallow binding on*', (tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
let tpl = `<div [attr.onclick]="ctxProp"></div>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then(v => async.done(new Error('unexpected success')))
.catch((e) => {
it('should disallow binding on*', () => {
const template = `<div [attr.onclick]="ctxProp"></div>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
try {
TestBed.createComponent(SecuredComponent);
throw 'Should throw';
} catch (e) {
expect(e.message).toContain(
`Template parse errors:\n` +
`Binding to event attribute 'onclick' is disallowed ` +
`for security reasons, please use (click)=... `);
async.done();
return null;
});
}
});
describe('safe HTML values', function() {
itAsync(
'should not escape values marked as trusted',
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
sanitizer: DomSanitizationService) => {
let tpl = `<a [href]="ctxProp">Link Title</a>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should not escape values marked as trusted', () => {
const template = `<a [href]="ctxProp">Link Title</a>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
let e = fixture.debugElement.children[0].nativeElement;
let ci = fixture.debugElement.componentInstance;
let trusted = sanitizer.bypassSecurityTrustUrl('javascript:alert(1)');
ci.ctxProp = trusted;
fixture.detectChanges();
expect(getDOM().getProperty(e, 'href')).toEqual('javascript:alert(1)');
async.done();
});
});
itAsync(
'should error when using the wrong trusted value',
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
sanitizer: DomSanitizationService) => {
let tpl = `<a [href]="ctxProp">Link Title</a>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should error when using the wrong trusted value', () => {
const template = `<a [href]="ctxProp">Link Title</a>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
let trusted = sanitizer.bypassSecurityTrustScript('javascript:alert(1)');
let ci = fixture.debugElement.componentInstance;
ci.ctxProp = trusted;
expect(() => fixture.detectChanges())
.toThrowError(/Required a safe URL, got a Script/);
async.done();
});
expect(() => fixture.detectChanges()).toThrowError(/Required a safe URL, got a Script/);
});
itAsync(
'should warn when using in string interpolation',
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
sanitizer: DomSanitizationService) => {
let tpl = `<a href="/foo/{{ctxProp}}">Link Title</a>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should warn when using in string interpolation', () => {
const template = `<a href="/foo/{{ctxProp}}">Link Title</a>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
let e = fixture.debugElement.children[0].nativeElement;
let trusted = sanitizer.bypassSecurityTrustUrl('bar/baz');
let ci = fixture.debugElement.componentInstance;
ci.ctxProp = trusted;
fixture.detectChanges();
expect(getDOM().getProperty(e, 'href')).toMatch(/SafeValue(%20| )must(%20| )use/);
async.done();
});
});
});
describe('sanitizing', () => {
itAsync(
'should escape unsafe attributes',
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
let tpl = `<a [href]="ctxProp">Link Title</a>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should escape unsafe attributes', () => {
const template = `<a [href]="ctxProp">Link Title</a>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
let e = fixture.debugElement.children[0].nativeElement;
let ci = fixture.debugElement.componentInstance;
ci.ctxProp = 'hello';
@ -148,18 +113,13 @@ function declareTests({useJit}: {useJit: boolean}) {
ci.ctxProp = 'javascript:alert(1)';
fixture.detectChanges();
expect(getDOM().getProperty(e, 'href')).toEqual('unsafe:javascript:alert(1)');
async.done();
});
});
itAsync(
'should escape unsafe style values',
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
let tpl = `<div [style.background]="ctxProp">Text</div>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should escape unsafe style values', () => {
const template = `<div [style.background]="ctxProp">Text</div>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
let e = fixture.debugElement.children[0].nativeElement;
let ci = fixture.debugElement.componentInstance;
// Make sure binding harmless values works.
@ -173,32 +133,25 @@ function declareTests({useJit}: {useJit: boolean}) {
fixture.detectChanges();
// Updated value gets rejected, no value change.
expect(getDOM().getStyle(e, 'background')).not.toContain('javascript');
async.done();
});
});
itAsync(
'should escape unsafe SVG attributes',
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
let tpl = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then(v => async.done(new Error('unexpected success')))
.catch((e) => {
it('should escape unsafe SVG attributes', () => {
const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
try {
TestBed.createComponent(SecuredComponent);
throw 'Should throw';
} catch (e) {
expect(e.message).toContain(`Can't bind to 'xlink:href'`);
async.done();
return null;
});
}
});
itAsync(
'should escape unsafe HTML values',
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
let tpl = `<div [innerHTML]="ctxProp">Text</div>`;
tcb.overrideTemplate(SecuredComponent, tpl)
.createAsync(SecuredComponent)
.then((fixture) => {
it('should escape unsafe HTML values', () => {
const template = `<div [innerHTML]="ctxProp">Text</div>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}});
const fixture = TestBed.createComponent(SecuredComponent);
let e = fixture.debugElement.children[0].nativeElement;
let ci = fixture.debugElement.componentInstance;
// Make sure binding harmless values works.
@ -217,9 +170,6 @@ function declareTests({useJit}: {useJit: boolean}) {
ci.ctxProp = 'also <iframe srcdoc="evil"></iframe> evil';
fixture.detectChanges();
expect(getDOM().getInnerHTML(e)).toEqual('also evil');
async.done();
});
});
});
});

View File

@ -9,63 +9,19 @@
import {NgFor, NgIf} from '@angular/common';
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, ElementRef, Host, Inject, InjectMetadata, Input, Optional, Pipe, PipeTransform, Self, SkipSelfMetadata, TemplateRef, Type, ViewContainerRef, forwardRef} from '@angular/core';
import {ViewMetadata} from '@angular/core/src/metadata/view';
import {ComponentFixture, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {TestComponentBuilder, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {ComponentFixture, TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/matchers';
import {isBlank} from '../../src/facade/lang';
const ALL_DIRECTIVES = [
forwardRef(() => SimpleDirective),
forwardRef(() => CycleDirective),
forwardRef(() => SimpleComponent),
forwardRef(() => SomeOtherDirective),
forwardRef(() => NeedsDirectiveFromSelf),
forwardRef(() => NeedsServiceComponent),
forwardRef(() => OptionallyNeedsDirective),
forwardRef(() => NeedsComponentFromHost),
forwardRef(() => NeedsDirectiveFromHost),
forwardRef(() => NeedsDirective),
forwardRef(() => NeedsService),
forwardRef(() => NeedsAppService),
forwardRef(() => NeedsAttribute),
forwardRef(() => NeedsAttributeNoType),
forwardRef(() => NeedsElementRef),
forwardRef(() => NeedsViewContainerRef),
forwardRef(() => NeedsTemplateRef),
forwardRef(() => OptionallyNeedsTemplateRef),
forwardRef(() => DirectiveNeedsChangeDetectorRef),
forwardRef(() => PushComponentNeedsChangeDetectorRef),
forwardRef(() => NeedsServiceFromHost),
forwardRef(() => NeedsAttribute),
forwardRef(() => NeedsAttributeNoType),
forwardRef(() => NeedsElementRef),
forwardRef(() => NeedsViewContainerRef),
forwardRef(() => NeedsTemplateRef),
forwardRef(() => OptionallyNeedsTemplateRef),
forwardRef(() => DirectiveNeedsChangeDetectorRef),
forwardRef(() => PushComponentNeedsChangeDetectorRef),
forwardRef(() => NeedsHostAppService),
NgIf,
NgFor
];
const ALL_PIPES = [
forwardRef(() => PipeNeedsChangeDetectorRef),
forwardRef(() => PipeNeedsService),
forwardRef(() => PurePipe),
forwardRef(() => ImpurePipe),
forwardRef(() => DuplicatePipe1),
forwardRef(() => DuplicatePipe2),
];
@Directive({selector: '[simpleDirective]'})
class SimpleDirective {
@Input('simpleDirective') value: any = null;
}
@Component({selector: '[simpleComponent]', template: '', directives: ALL_DIRECTIVES})
@Component({selector: '[simpleComponent]', template: ''})
class SimpleComponent {
}
@ -111,40 +67,38 @@ class NeedsDirective {
@Directive({selector: '[needsService]'})
class NeedsService {
service: any;
constructor(@Inject('service') service: any /** TODO #9100 */) { this.service = service; }
constructor(@Inject('service') service: any) { this.service = service; }
}
@Directive({selector: '[needsAppService]'})
class NeedsAppService {
service: any;
constructor(@Inject('appService') service: any /** TODO #9100 */) { this.service = service; }
constructor(@Inject('appService') service: any) { this.service = service; }
}
@Component({selector: '[needsHostAppService]', template: '', directives: ALL_DIRECTIVES})
@Component({selector: '[needsHostAppService]', template: ''})
class NeedsHostAppService {
service: any;
constructor(@Host() @Inject('appService') service: any /** TODO #9100 */) {
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 /** TODO #9100 */) { this.service = service; }
constructor(@Inject('service') service: any) { this.service = service; }
}
@Directive({selector: '[needsServiceFromHost]'})
class NeedsServiceFromHost {
service: any;
constructor(@Host() @Inject('service') service: any /** TODO #9100 */) { this.service = service; }
constructor(@Host() @Inject('service') service: any) { this.service = service; }
}
@Directive({selector: '[needsAttribute]'})
class NeedsAttribute {
typeAttribute: any /** TODO #9100 */;
titleAttribute: any /** TODO #9100 */;
fooAttribute: any /** TODO #9100 */;
typeAttribute: any;
titleAttribute: any;
fooAttribute: any;
constructor(
@Attribute('type') typeAttribute: String, @Attribute('title') titleAttribute: String,
@Attribute('foo') fooAttribute: String) {
@ -156,33 +110,31 @@ class NeedsAttribute {
@Directive({selector: '[needsAttributeNoType]'})
class NeedsAttributeNoType {
fooAttribute: any /** TODO #9100 */;
constructor(@Attribute('foo') fooAttribute: any /** TODO #9100 */) {
this.fooAttribute = fooAttribute;
}
fooAttribute: any;
constructor(@Attribute('foo') fooAttribute: any) { this.fooAttribute = fooAttribute; }
}
@Directive({selector: '[needsElementRef]'})
class NeedsElementRef {
elementRef: any /** TODO #9100 */;
elementRef: any;
constructor(ref: ElementRef) { this.elementRef = ref; }
}
@Directive({selector: '[needsViewContainerRef]'})
class NeedsViewContainerRef {
viewContainer: any /** TODO #9100 */;
viewContainer: any;
constructor(vc: ViewContainerRef) { this.viewContainer = vc; }
}
@Directive({selector: '[needsTemplateRef]'})
class NeedsTemplateRef {
templateRef: any /** TODO #9100 */;
templateRef: any;
constructor(ref: TemplateRef<Object>) { this.templateRef = ref; }
}
@Directive({selector: '[optionallyNeedsTemplateRef]'})
class OptionallyNeedsTemplateRef {
templateRef: any /** TODO #9100 */;
templateRef: any;
constructor(@Optional() ref: TemplateRef<Object>) { this.templateRef = ref; }
}
@ -194,7 +146,6 @@ class DirectiveNeedsChangeDetectorRef {
@Component({
selector: '[componentNeedsChangeDetectorRef]',
template: '{{counter}}',
directives: ALL_DIRECTIVES,
changeDetection: ChangeDetectionStrategy.OnPush
})
class PushComponentNeedsChangeDetectorRef {
@ -223,7 +174,7 @@ class PipeNeedsChangeDetectorRef {
@Pipe({name: 'pipeNeedsService'})
export class PipeNeedsService implements PipeTransform {
service: any;
constructor(@Inject('service') service: any /** TODO #9100 */) { this.service = service; }
constructor(@Inject('service') service: any) { this.service = service; }
transform(value: any): any { return this; }
}
@ -237,58 +188,57 @@ export class DuplicatePipe2 implements PipeTransform {
transform(value: any): any { return this; }
}
@Component({selector: 'root'})
@Component({selector: 'root', template: ''})
class TestComp {
}
export function main() {
var tcb: TestComponentBuilder;
function createCompFixture<T>(
template: string, tcb: TestComponentBuilder, comp: Type<T> = null): ComponentFixture<T> {
if (isBlank(comp)) {
function createComponentFixture<T>(
template: string, providers: any[] = null, comp: Type<T> = null): ComponentFixture<T> {
if (!comp) {
comp = <any>TestComp;
}
return tcb
.overrideView(
comp,
new ViewMetadata({template: template, directives: ALL_DIRECTIVES, pipes: ALL_PIPES}))
.createFakeAsync(comp);
TestBed.overrideComponent(comp, {set: {template}});
if (providers && providers.length) {
TestBed.overrideComponent(comp, {add: {providers: providers}});
}
return TestBed.createComponent(comp);
}
function createComp(
template: string, tcb: TestComponentBuilder, comp: Type<any> = null): DebugElement {
var fixture = createCompFixture(template, tcb, comp);
function createComponent(
template: string, providers: any[] = null, comp: Type<any> = null): DebugElement {
const fixture = createComponentFixture(template, providers, comp);
fixture.detectChanges();
return fixture.debugElement;
}
describe('View Injector', () => {
describe('View injector', () => {
// On CJS fakeAsync is not supported...
if (!getDOM().supportsDOMEvents()) return;
beforeEach(() => TestBed.configureTestingModule({declarations: [TestComp]}));
beforeEachProviders(() => [{provide: 'appService', useValue: 'appService'}]);
beforeEach(
fakeAsync(inject([TestComponentBuilder], (_tcb: TestComponentBuilder) => { tcb = _tcb; })));
describe('injection', () => {
it('should instantiate directives that have no dependencies', fakeAsync(() => {
var el = createComp('<div simpleDirective>', tcb);
it('should instantiate directives that have no dependencies', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective]});
const el = createComponent('<div simpleDirective>');
expect(el.children[0].injector.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
}));
});
it('should instantiate directives that depend on another directive', fakeAsync(() => {
var el = createComp('<div simpleDirective needsDirective>', tcb);
it('should instantiate directives that depend on another directive', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]});
const el = createComponent('<div simpleDirective needsDirective>');
var d = el.children[0].injector.get(NeedsDirective);
expect(d).toBeAnInstanceOf(NeedsDirective);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}));
});
it('should support useValue with different values', fakeAsync(() => {
var el = createComp('', tcb.overrideProviders(TestComp, [
it('should support useValue with different values', () => {
const el = createComponent('', [
{provide: 'numLiteral', useValue: 0},
{provide: 'boolLiteral', useValue: true},
{provide: 'strLiteral', useValue: 'a'},
@ -297,7 +247,7 @@ export function main() {
{provide: 'map', useValue: {'a': 1}},
{provide: 'instance', useValue: new TestValue('a')},
{provide: 'nested', useValue: [{'a': [1]}, new TestValue('b')]},
]));
]);
expect(el.injector.get('numLiteral')).toBe(0);
expect(el.injector.get('boolLiteral')).toBe(true);
expect(el.injector.get('strLiteral')).toBe('a');
@ -306,424 +256,475 @@ export function main() {
expect(el.injector.get('map')).toEqual({'a': 1});
expect(el.injector.get('instance')).toEqual(new TestValue('a'));
expect(el.injector.get('nested')).toEqual([{'a': [1]}, new TestValue('b')]);
}));
});
it('should instantiate providers that have dependencies with SkipSelf', fakeAsync(() => {
var el = createComp(
'<div simpleDirective><span someOtherDirective></span></div>',
tcb.overrideProviders(
SimpleDirective, [{provide: 'injectable1', useValue: 'injectable1'}])
.overrideProviders(SomeOtherDirective, [
it('should instantiate providers that have dependencies with SkipSelf', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, SomeOtherDirective]});
TestBed.overrideDirective(
SimpleDirective,
{add: {providers: [{provide: 'injectable1', useValue: 'injectable1'}]}});
TestBed.overrideDirective(SomeOtherDirective, {
add: {
providers: [
{provide: 'injectable1', useValue: 'new-injectable1'}, {
provide: 'injectable2',
useFactory: (val: any /** TODO #9100 */) => `${val}-injectable2`,
useFactory: (val: any) => `${val}-injectable2`,
deps: [[new InjectMetadata('injectable1'), new SkipSelfMetadata()]]
}
]));
]
}
});
const el = createComponent('<div simpleDirective><span someOtherDirective></span></div>');
expect(el.children[0].children[0].injector.get('injectable2'))
.toEqual('injectable1-injectable2');
}));
});
it('should instantiate providers that have dependencies', fakeAsync(() => {
var providers = [
it('should instantiate providers that have dependencies', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective]});
const providers = [
{provide: 'injectable1', useValue: 'injectable1'}, {
provide: 'injectable2',
useFactory: (val: any /** TODO #9100 */) => `${val}-injectable2`,
useFactory: (val: any) => `${val}-injectable2`,
deps: ['injectable1']
}
];
var el = createComp(
'<div simpleDirective></div>', tcb.overrideProviders(SimpleDirective, providers));
TestBed.overrideDirective(SimpleDirective, {add: {providers}});
var el = createComponent('<div simpleDirective></div>');
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
}));
});
it('should instantiate viewProviders that have dependencies', fakeAsync(() => {
var viewProviders = [
it('should instantiate viewProviders that have dependencies', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent]});
const viewProviders = [
{provide: 'injectable1', useValue: 'injectable1'}, {
provide: 'injectable2',
useFactory: (val: any /** TODO #9100 */) => `${val}-injectable2`,
useFactory: (val: any) => `${val}-injectable2`,
deps: ['injectable1']
}
];
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideViewProviders(SimpleComponent, viewProviders));
TestBed.overrideComponent(SimpleComponent, {set: {viewProviders}});
const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
}));
});
it('should instantiate components that depend on viewProviders providers', fakeAsync(() => {
var el = createComp(
'<div needsServiceComponent></div>',
tcb.overrideViewProviders(
NeedsServiceComponent, [{provide: 'service', useValue: 'service'}]));
it('should instantiate components that depend on viewProviders providers', () => {
TestBed.configureTestingModule({declarations: [NeedsServiceComponent]});
TestBed.overrideComponent(
NeedsServiceComponent, {set: {providers: [{provide: 'service', useValue: 'service'}]}});
const el = createComponent('<div needsServiceComponent></div>');
expect(el.children[0].injector.get(NeedsServiceComponent).service).toEqual('service');
}));
});
it('should instantiate multi providers', fakeAsync(() => {
var providers = [
it('should instantiate multi providers', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective]});
const providers = [
{provide: 'injectable1', useValue: 'injectable11', multi: true},
{provide: 'injectable1', useValue: 'injectable12', multi: true}
];
var el = createComp(
'<div simpleDirective></div>', tcb.overrideProviders(SimpleDirective, providers));
TestBed.overrideDirective(SimpleDirective, {set: {providers}});
const el = createComponent('<div simpleDirective></div>');
expect(el.children[0].injector.get('injectable1')).toEqual([
'injectable11', 'injectable12'
]);
}));
});
it('should instantiate providers lazily', fakeAsync(() => {
var created = false;
var el = createComp(
'<div simpleDirective></div>',
tcb.overrideProviders(
SimpleDirective, [{provide: 'service', useFactory: () => created = true}]));
it('should instantiate providers lazily', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective]});
let created = false;
TestBed.overrideDirective(
SimpleDirective,
{set: {providers: [{provide: 'service', useFactory: () => created = true}]}});
const el = createComponent('<div simpleDirective></div>');
expect(created).toBe(false);
el.children[0].injector.get('service');
expect(created).toBe(true);
}));
});
it('should instantiate providers with a lifecycle hook eagerly', fakeAsync(() => {
var created = false;
it('should instantiate providers lazily', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective]});
let created = false;
TestBed.overrideDirective(
SimpleDirective,
{set: {providers: [{provide: 'service', useFactory: () => created = true}]}});
const el = createComponent('<div simpleDirective></div>');
expect(created).toBe(false);
el.children[0].injector.get('service');
expect(created).toBe(true);
});
it('should instantiate providers with a lifecycle hook eagerly', () => {
let created = false;
class SomeInjectable {
constructor() { created = true; }
ngOnDestroy() {}
}
TestBed.configureTestingModule({declarations: [SimpleDirective]});
TestBed.overrideDirective(SimpleDirective, {set: {providers: [SomeInjectable]}});
var el = createComp(
'<div simpleDirective></div>',
tcb.overrideProviders(SimpleDirective, [SomeInjectable]));
const el = createComponent('<div simpleDirective></div>');
expect(created).toBe(true);
}));
});
it('should instantiate view providers lazily', fakeAsync(() => {
var created = false;
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideViewProviders(
SimpleComponent, [{provide: 'service', useFactory: () => created = true}]));
it('should instantiate view providers lazily', () => {
let created = false;
TestBed.configureTestingModule({declarations: [SimpleComponent]});
TestBed.overrideComponent(
SimpleComponent,
{set: {viewProviders: [{provide: 'service', useFactory: () => created = true}]}});
const el = createComponent('<div simpleComponent></div>');
expect(created).toBe(false);
el.children[0].injector.get('service');
expect(created).toBe(true);
}));
});
it('should not instantiate other directives that depend on viewProviders providers (same element)',
fakeAsync(() => {
expect(
() => createComp(
'<div simpleComponent needsService></div>',
tcb.overrideViewProviders(
SimpleComponent, [{provide: 'service', useValue: 'service'}])))
() => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent(
SimpleComponent,
{set: {viewProviders: [{provide: 'service', useValue: 'service'}]}});
expect(() => createComponent('<div simpleComponent needsService></div>'))
.toThrowError(/No provider for service!/);
}));
});
it('should not instantiate other directives that depend on viewProviders providers (child element)',
fakeAsync(() => {
expect(
() => createComp(
'<div simpleComponent><div needsService></div></div>',
tcb.overrideViewProviders(
SimpleComponent, [{provide: 'service', useValue: 'service'}])))
() => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent(
SimpleComponent,
{set: {viewProviders: [{provide: 'service', useValue: 'service'}]}});
expect(() => createComponent('<div simpleComponent><div needsService></div></div>'))
.toThrowError(/No provider for service!/);
}));
});
it('should instantiate directives that depend on providers of other directives',
fakeAsync(() => {
var el = createComp(
'<div simpleDirective><div needsService></div></div>',
tcb.overrideProviders(
SimpleDirective, [{provide: 'service', useValue: 'parentService'}]));
it('should instantiate directives that depend on providers of other directives', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]});
TestBed.overrideDirective(
SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}});
const el = createComponent('<div simpleDirective><div needsService></div></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('parentService');
}));
});
it('should instantiate directives that depend on providers in a parent view',
fakeAsync(() => {
var el = createComp(
'<div simpleDirective><template [ngIf]="true"><div *ngIf="true" needsService></div></template></div>',
tcb.overrideProviders(
SimpleDirective, [{provide: 'service', useValue: 'parentService'}]));
it('should instantiate directives that depend on providers in a parent view', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]});
TestBed.overrideDirective(
SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}});
const el = createComponent(
'<div simpleDirective><template [ngIf]="true"><div *ngIf="true" needsService></div></template></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('parentService');
}));
});
it('should instantiate directives that depend on providers of a component', fakeAsync(() => {
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideTemplate(SimpleComponent, '<div needsService></div>')
.overrideProviders(
SimpleComponent, [{provide: 'service', useValue: 'hostService'}]));
it('should instantiate directives that depend on providers of a component', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent(
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}});
const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('hostService');
}));
});
it('should instantiate directives that depend on view providers of a component',
fakeAsync(() => {
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideTemplate(SimpleComponent, '<div needsService></div>')
.overrideViewProviders(
SimpleComponent, [{provide: 'service', useValue: 'hostService'}]));
it('should instantiate directives that depend on view providers of a component', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent(
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}});
const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('hostService');
}));
});
it('should instantiate directives in a root embedded view that depend on view providers of a component',
fakeAsync(() => {
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideTemplate(SimpleComponent, '<div *ngIf="true" needsService></div>')
.overrideViewProviders(
SimpleComponent, [{provide: 'service', useValue: 'hostService'}]));
() => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div *ngIf="true" needsService></div>'}});
const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('hostService');
}));
});
it('should instantiate directives that depend on instances in the app injector',
fakeAsync(() => {
var el = createComp('<div needsAppService></div>', tcb);
it('should instantiate directives that depend on instances in the app injector', () => {
TestBed.configureTestingModule({declarations: [NeedsAppService]});
const el = createComponent('<div needsAppService></div>');
expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService');
}));
});
it('should not instantiate a directive with cyclic dependencies', fakeAsync(() => {
expect(() => createComp('<div cycleDirective></div>', tcb))
it('should not instantiate a directive with cyclic dependencies', () => {
TestBed.configureTestingModule({declarations: [CycleDirective]});
expect(() => createComponent('<div cycleDirective></div>'))
.toThrowError(
'Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective ("[ERROR ->]<div cycleDirective></div>"): TestComp@0:0');
}));
});
it('should not instantiate a directive in a view that has a host dependency on providers' +
' of the component',
fakeAsync(() => {
expect(
() => createComp(
'<div simpleComponent></div>',
tcb.overrideProviders(
SimpleComponent, [{provide: 'service', useValue: 'hostService'}])
.overrideTemplate(SimpleComponent, '<div needsServiceFromHost><div>')))
() => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent></div>'))
.toThrowError(
`Template parse errors:\nNo provider for service ("[ERROR ->]<div needsServiceFromHost><div>"): SimpleComponent@0:0`);
}));
});
it('should not instantiate a directive in a view that has a host dependency on providers' +
' of a decorator directive',
fakeAsync(() => {
expect(
() => createComp(
'<div simpleComponent someOtherDirective></div>',
tcb.overrideProviders(
SomeOtherDirective, [{provide: 'service', useValue: 'hostService'}])
.overrideTemplate(SimpleComponent, '<div needsServiceFromHost><div>')))
() => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
.toThrowError(
`Template parse errors:\nNo provider for service ("[ERROR ->]<div needsServiceFromHost><div>"): SimpleComponent@0:0`);
}));
});
it('should not instantiate a directive in a view that has a self dependency on a parent directive',
fakeAsync(() => {
() => {
TestBed.configureTestingModule(
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
expect(
() =>
createComp('<div simpleDirective><div needsDirectiveFromSelf></div></div>', tcb))
createComponent('<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
.toThrowError(
`Template parse errors:\nNo provider for SimpleDirective ("<div simpleDirective>[ERROR ->]<div needsDirectiveFromSelf></div></div>"): TestComp@0:21`);
}));
});
it('should instantiate directives that depend on other directives', fakeAsync(() => {
var el = createComp('<div simpleDirective><div needsDirective></div></div>', tcb);
var d = el.children[0].children[0].injector.get(NeedsDirective);
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]});
const el = createComponent('<div simpleDirective><div needsDirective></div></div>');
const d = el.children[0].children[0].injector.get(NeedsDirective);
expect(d).toBeAnInstanceOf(NeedsDirective);
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}));
it('should throw when a dependency cannot be resolved', fakeAsync(() => {
expect(() => createComp('<div needsService></div>', tcb))
TestBed.configureTestingModule({declarations: [NeedsService]});
expect(() => createComponent('<div needsService></div>'))
.toThrowError(/No provider for service!/);
}));
it('should inject null when an optional dependency cannot be resolved', fakeAsync(() => {
var el = createComp('<div optionallyNeedsDirective></div>', tcb);
var d = el.children[0].injector.get(OptionallyNeedsDirective);
it('should inject null when an optional dependency cannot be resolved', () => {
TestBed.configureTestingModule({declarations: [OptionallyNeedsDirective]});
const el = createComponent('<div optionallyNeedsDirective></div>');
const d = el.children[0].injector.get(OptionallyNeedsDirective);
expect(d.dependency).toEqual(null);
}));
});
it('should instantiate directives that depends on the host component', fakeAsync(() => {
var el = createComp(
'<div simpleComponent></div>',
tcb.overrideTemplate(SimpleComponent, '<div needsComponentFromHost></div>'));
var d = el.children[0].children[0].injector.get(NeedsComponentFromHost);
it('should instantiate directives that depends on the host component', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsComponentFromHost]});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsComponentFromHost></div>'}});
const el = createComponent('<div simpleComponent></div>');
const d = el.children[0].children[0].injector.get(NeedsComponentFromHost);
expect(d.dependency).toBeAnInstanceOf(SimpleComponent);
}));
});
it('should instantiate host views for components that have a @Host dependency ',
fakeAsync(() => {
var el = createComp('', tcb, NeedsHostAppService);
it('should instantiate host views for components that have a @Host dependency ', () => {
TestBed.configureTestingModule({declarations: [NeedsHostAppService]});
const el = createComponent('', [], NeedsHostAppService);
expect(el.componentInstance.service).toEqual('appService');
}));
});
it('should not instantiate directives that depend on other directives on the host element',
fakeAsync(() => {
expect(
() => createComp(
'<div simpleComponent simpleDirective></div>',
tcb.overrideTemplate(SimpleComponent, '<div needsDirectiveFromHost></div>')))
it('should not instantiate directives that depend on other directives on the host element', () => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}});
expect(() => createComponent('<div simpleComponent simpleDirective></div>'))
.toThrowError(
`Template parse errors:\nNo provider for SimpleDirective ("[ERROR ->]<div needsDirectiveFromHost></div>"): SimpleComponent@0:0`);
}));
});
});
describe('static attributes', () => {
it('should be injectable', fakeAsync(() => {
var el = createComp('<div needsAttribute type="text" title></div>', tcb);
var needsAttribute = el.children[0].injector.get(NeedsAttribute);
it('should be injectable', () => {
TestBed.configureTestingModule({declarations: [NeedsAttribute]});
const el = createComponent('<div needsAttribute type="text" title></div>');
const needsAttribute = el.children[0].injector.get(NeedsAttribute);
expect(needsAttribute.typeAttribute).toEqual('text');
expect(needsAttribute.titleAttribute).toEqual('');
expect(needsAttribute.fooAttribute).toEqual(null);
}));
});
it('should be injectable without type annotation', fakeAsync(() => {
var el = createComp('<div needsAttributeNoType foo="bar"></div>', tcb);
var needsAttribute = el.children[0].injector.get(NeedsAttributeNoType);
it('should be injectable without type annotation', () => {
TestBed.configureTestingModule({declarations: [NeedsAttributeNoType]});
const el = createComponent('<div needsAttributeNoType foo="bar"></div>');
const needsAttribute = el.children[0].injector.get(NeedsAttributeNoType);
expect(needsAttribute.fooAttribute).toEqual('bar');
}));
});
});
describe('refs', () => {
it('should inject ElementRef', fakeAsync(() => {
var el = createComp('<div needsElementRef></div>', tcb);
it('should inject ElementRef', () => {
TestBed.configureTestingModule({declarations: [NeedsElementRef]});
const el = createComponent('<div needsElementRef></div>');
expect(el.children[0].injector.get(NeedsElementRef).elementRef.nativeElement)
.toBe(el.children[0].nativeElement);
}));
});
it('should inject ChangeDetectorRef of the component\'s view into the component via a proxy',
fakeAsync(() => {
var cf = createCompFixture('<div componentNeedsChangeDetectorRef></div>', tcb);
() => {
TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]});
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
cf.detectChanges();
var compEl = cf.debugElement.children[0];
var comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
const compEl = cf.debugElement.children[0];
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
comp.counter = 1;
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0');
comp.changeDetectorRef.markForCheck();
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('1');
}));
});
it('should inject ChangeDetectorRef of the containing component into directives',
fakeAsync(() => {
var cf = createCompFixture(
'<div componentNeedsChangeDetectorRef></div>',
tcb.overrideTemplate(
PushComponentNeedsChangeDetectorRef,
'{{counter}}<div directiveNeedsChangeDetectorRef></div><div *ngIf="true" directiveNeedsChangeDetectorRef></div>'));
it('should inject ChangeDetectorRef of the containing component into directives', () => {
TestBed.configureTestingModule(
{declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]});
TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, {
set: {
template:
'{{counter}}<div directiveNeedsChangeDetectorRef></div><div *ngIf="true" directiveNeedsChangeDetectorRef></div>'
}
});
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
cf.detectChanges();
var compEl = cf.debugElement.children[0];
var comp: PushComponentNeedsChangeDetectorRef =
const compEl = cf.debugElement.children[0];
const comp: PushComponentNeedsChangeDetectorRef =
compEl.injector.get(PushComponentNeedsChangeDetectorRef);
comp.counter = 1;
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0');
expect(
compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
expect(compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
.toBe(comp.changeDetectorRef);
expect(
compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
expect(compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
.toBe(comp.changeDetectorRef);
comp.changeDetectorRef.markForCheck();
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('1');
}));
});
it('should inject ViewContainerRef', fakeAsync(() => {
var el = createComp('<div needsViewContainerRef></div>', tcb);
expect(el.children[0]
.injector.get(NeedsViewContainerRef)
.viewContainer.element.nativeElement)
it('should inject ViewContainerRef', () => {
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]});
const el = createComponent('<div needsViewContainerRef></div>');
expect(
el.children[0].injector.get(NeedsViewContainerRef).viewContainer.element.nativeElement)
.toBe(el.children[0].nativeElement);
}));
});
it('should inject TemplateRef', fakeAsync(() => {
var el = createComp('<template needsViewContainerRef needsTemplateRef></template>', tcb);
it('should inject TemplateRef', () => {
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef, NeedsTemplateRef]});
const el = createComponent('<template needsViewContainerRef needsTemplateRef></template>');
expect(el.childNodes[0].injector.get(NeedsTemplateRef).templateRef.elementRef)
.toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element);
}));
});
it('should throw if there is no TemplateRef', fakeAsync(() => {
expect(() => createComp('<div needsTemplateRef></div>', tcb))
it('should throw if there is no TemplateRef', () => {
TestBed.configureTestingModule({declarations: [NeedsTemplateRef]});
expect(() => createComponent('<div needsTemplateRef></div>'))
.toThrowError(/No provider for TemplateRef!/);
}));
});
it('should inject null if there is no TemplateRef when the dependency is optional',
fakeAsync(() => {
var el = createComp('<div optionallyNeedsTemplateRef></div>', tcb);
var instance = el.children[0].injector.get(OptionallyNeedsTemplateRef);
it('should inject null if there is no TemplateRef when the dependency is optional', () => {
TestBed.configureTestingModule({declarations: [OptionallyNeedsTemplateRef]});
const el = createComponent('<div optionallyNeedsTemplateRef></div>');
const instance = el.children[0].injector.get(OptionallyNeedsTemplateRef);
expect(instance.templateRef).toBeNull();
}));
});
});
describe('pipes', () => {
it('should instantiate pipes that have dependencies', fakeAsync(() => {
var el = createComp(
it('should instantiate pipes that have dependencies', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, PipeNeedsService]});
const el = createComponent(
'<div [simpleDirective]="true | pipeNeedsService"></div>',
tcb.overrideProviders(TestComp, [{provide: 'service', useValue: 'pipeService'}]));
expect(el.children[0].injector.get(SimpleDirective).value.service)
.toEqual('pipeService');
}));
[{provide: 'service', useValue: 'pipeService'}]);
expect(el.children[0].injector.get(SimpleDirective).value.service).toEqual('pipeService');
});
it('should overwrite pipes with later entry in the pipes array', fakeAsync(() => {
var el = createComp('<div [simpleDirective]="true | duplicatePipe"></div>', tcb);
expect(el.children[0].injector.get(SimpleDirective).value)
.toBeAnInstanceOf(DuplicatePipe2);
}));
it('should overwrite pipes with later entry in the pipes array', () => {
TestBed.configureTestingModule(
{declarations: [SimpleDirective, DuplicatePipe1, DuplicatePipe2]});
const el = createComponent('<div [simpleDirective]="true | duplicatePipe"></div>');
expect(el.children[0].injector.get(SimpleDirective).value).toBeAnInstanceOf(DuplicatePipe2);
});
it('should inject ChangeDetectorRef into pipes', fakeAsync(() => {
var el = createComp(
'<div [simpleDirective]="true | pipeNeedsChangeDetectorRef" directiveNeedsChangeDetectorRef></div>',
tcb);
var cdRef =
it('should inject ChangeDetectorRef into pipes', () => {
TestBed.configureTestingModule({
declarations:
[SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
});
const el = createComponent(
'<div [simpleDirective]="true | pipeNeedsChangeDetectorRef" directiveNeedsChangeDetectorRef></div>');
const cdRef =
el.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef;
expect(el.children[0].injector.get(SimpleDirective).value.changeDetectorRef).toBe(cdRef);
}));
});
it('should cache pure pipes', fakeAsync(() => {
var el = createComp(
it('should cache pure pipes', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, PurePipe]});
const el = createComponent(
'<div [simpleDirective]="true | purePipe"></div><div [simpleDirective]="true | purePipe"></div>' +
'<div *ngFor="let x of [1,2]" [simpleDirective]="true | purePipe"></div>',
tcb);
var purePipe1 = el.children[0].injector.get(SimpleDirective).value;
var purePipe2 = el.children[1].injector.get(SimpleDirective).value;
var purePipe3 = el.children[2].injector.get(SimpleDirective).value;
var purePipe4 = el.children[3].injector.get(SimpleDirective).value;
'<div *ngFor="let x of [1,2]" [simpleDirective]="true | purePipe"></div>');
const purePipe1 = el.children[0].injector.get(SimpleDirective).value;
const purePipe2 = el.children[1].injector.get(SimpleDirective).value;
const purePipe3 = el.children[2].injector.get(SimpleDirective).value;
const purePipe4 = el.children[3].injector.get(SimpleDirective).value;
expect(purePipe1).toBeAnInstanceOf(PurePipe);
expect(purePipe2).toBe(purePipe1);
expect(purePipe3).toBe(purePipe1);
expect(purePipe4).toBe(purePipe1);
}));
});
it('should not cache impure pipes', fakeAsync(() => {
var el = createComp(
it('should not cache impure pipes', () => {
TestBed.configureTestingModule({declarations: [SimpleDirective, ImpurePipe]});
const el = createComponent(
'<div [simpleDirective]="true | impurePipe"></div><div [simpleDirective]="true | impurePipe"></div>' +
'<div *ngFor="let x of [1,2]" [simpleDirective]="true | impurePipe"></div>',
tcb);
var purePipe1 = el.children[0].injector.get(SimpleDirective).value;
var purePipe2 = el.children[1].injector.get(SimpleDirective).value;
var purePipe3 = el.children[2].injector.get(SimpleDirective).value;
var purePipe4 = el.children[3].injector.get(SimpleDirective).value;
expect(purePipe1).toBeAnInstanceOf(ImpurePipe);
expect(purePipe2).toBeAnInstanceOf(ImpurePipe);
expect(purePipe2).not.toBe(purePipe1);
expect(purePipe3).toBeAnInstanceOf(ImpurePipe);
expect(purePipe3).not.toBe(purePipe1);
expect(purePipe4).toBeAnInstanceOf(ImpurePipe);
expect(purePipe4).not.toBe(purePipe1);
}));
'<div *ngFor="let x of [1,2]" [simpleDirective]="true | impurePipe"></div>');
const impurePipe1 = el.children[0].injector.get(SimpleDirective).value;
const impurePipe2 = el.children[1].injector.get(SimpleDirective).value;
const impurePipe3 = el.children[2].injector.get(SimpleDirective).value;
const impurePipe4 = el.children[3].injector.get(SimpleDirective).value;
expect(impurePipe1).toBeAnInstanceOf(ImpurePipe);
expect(impurePipe2).toBeAnInstanceOf(ImpurePipe);
expect(impurePipe2).not.toBe(impurePipe1);
expect(impurePipe3).toBeAnInstanceOf(ImpurePipe);
expect(impurePipe3).not.toBe(impurePipe1);
expect(impurePipe4).toBeAnInstanceOf(ImpurePipe);
expect(impurePipe4).not.toBe(impurePipe1);
});
});
});
}