675 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			675 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 
								 | 
							
								// #docplaster
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  BagModule,
							 | 
						||
| 
								 | 
							
								  BankAccountComponent, BankAccountParentComponent,
							 | 
						||
| 
								 | 
							
								  ButtonComponent,
							 | 
						||
| 
								 | 
							
								  Child1Component, Child2Component, Child3Component,
							 | 
						||
| 
								 | 
							
								  FancyService,
							 | 
						||
| 
								 | 
							
								  ExternalTemplateComponent,
							 | 
						||
| 
								 | 
							
								  InputComponent,
							 | 
						||
| 
								 | 
							
								  IoComponent, IoParentComponent,
							 | 
						||
| 
								 | 
							
								  MyIfComponent, MyIfChildComponent, MyIfParentComponent,
							 | 
						||
| 
								 | 
							
								  NeedsContentComponent, ParentComponent,
							 | 
						||
| 
								 | 
							
								  TestProvidersComponent, TestViewProvidersComponent,
							 | 
						||
| 
								 | 
							
								  ReversePipeComponent, ShellComponent
							 | 
						||
| 
								 | 
							
								} from './bag';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { By }          from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { Component,
							 | 
						||
| 
								 | 
							
								         DebugElement,
							 | 
						||
| 
								 | 
							
								         Injectable }  from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { FormsModule } from '@angular/forms';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Forms symbols imported only for a specific test below
							 | 
						||
| 
								 | 
							
								import { NgModel, NgControl } from '@angular/forms';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { async, ComponentFixture, fakeAsync, inject, TestBed, tick
							 | 
						||
| 
								 | 
							
								} from '@angular/core/testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { addMatchers, newEvent } from '../../testing';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								beforeEach( addMatchers );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////  Service Tests  /////////////
							 | 
						||
| 
								 | 
							
								// #docregion FancyService
							 | 
						||
| 
								 | 
							
								describe('use inject helper in beforeEach', () => {
							 | 
						||
| 
								 | 
							
								  let service: FancyService;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({ providers: [FancyService] });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // `TestBed.get` returns the injectable or an
							 | 
						||
| 
								 | 
							
								    //  alternative object (including null) if the service provider is not found.
							 | 
						||
| 
								 | 
							
								    //  Of course it will be found in this case because we're providing it.
							 | 
						||
| 
								 | 
							
								    // #docregion testbed-get
							 | 
						||
| 
								 | 
							
								    service = TestBed.get(FancyService, null);
							 | 
						||
| 
								 | 
							
								    // #enddocregion testbed-get
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should use FancyService', () => {
							 | 
						||
| 
								 | 
							
								      expect(service.getValue()).toBe('real value');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should use FancyService', () => {
							 | 
						||
| 
								 | 
							
								      expect(service.getValue()).toBe('real value');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('test should wait for FancyService.getAsyncValue', async(() => {
							 | 
						||
| 
								 | 
							
								    service.getAsyncValue().then(
							 | 
						||
| 
								 | 
							
								      value => expect(value).toBe('async value')
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('test should wait for FancyService.getTimeoutValue', async(() => {
							 | 
						||
| 
								 | 
							
								    service.getTimeoutValue().then(
							 | 
						||
| 
								 | 
							
								      value => expect(value).toBe('timeout value')
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('test should wait for FancyService.getObservableValue', async(() => {
							 | 
						||
| 
								 | 
							
								    service.getObservableValue().subscribe(
							 | 
						||
| 
								 | 
							
								      value => expect(value).toBe('observable value')
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #enddocregion FancyService
							 | 
						||
| 
								 | 
							
								  // See https://github.com/angular/angular/issues/10127
							 | 
						||
| 
								 | 
							
								  xit('test should wait for FancyService.getObservableDelayValue', async(() => {
							 | 
						||
| 
								 | 
							
								    service.getObservableDelayValue().subscribe(
							 | 
						||
| 
								 | 
							
								      value => expect(value).toBe('observable delay value')
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								  // #docregion FancyService
							 | 
						||
| 
								 | 
							
								  it('should allow the use of fakeAsync', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    let value: any;
							 | 
						||
| 
								 | 
							
								    service.getAsyncValue().then((val: any) => value = val);
							 | 
						||
| 
								 | 
							
								    tick(); // Trigger JS engine cycle until all promises resolve.
							 | 
						||
| 
								 | 
							
								    expect(value).toBe('async value');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								// #enddocregion FancyService
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('use inject within `it`', () => {
							 | 
						||
| 
								 | 
							
								  // #docregion getTimeoutValue
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({ providers: [FancyService] });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #enddocregion getTimeoutValue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should use modified providers',
							 | 
						||
| 
								 | 
							
								    inject([FancyService], (service: FancyService) => {
							 | 
						||
| 
								 | 
							
								      service.setValue('value modified in beforeEach');
							 | 
						||
| 
								 | 
							
								      expect(service.getValue()).toBe('value modified in beforeEach');
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #docregion getTimeoutValue
							 | 
						||
| 
								 | 
							
								  it('test should wait for FancyService.getTimeoutValue',
							 | 
						||
| 
								 | 
							
								    async(inject([FancyService], (service: FancyService) => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    service.getTimeoutValue().then(
							 | 
						||
| 
								 | 
							
								      value => expect(value).toBe('timeout value')
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  })));
							 | 
						||
| 
								 | 
							
								  // #enddocregion getTimeoutValue
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('using async(inject) within beforeEach', () => {
							 | 
						||
| 
								 | 
							
								  let serviceValue: string;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({ providers: [FancyService] });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(inject([FancyService], (service: FancyService) => {
							 | 
						||
| 
								 | 
							
								    service.getAsyncValue().then(value => serviceValue = value);
							 | 
						||
| 
								 | 
							
								  })));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should use asynchronously modified value ... in synchronous test', () => {
							 | 
						||
| 
								 | 
							
								    expect(serviceValue).toBe('async value');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/////////// Component Tests //////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('TestBed Component Tests', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed
							 | 
						||
| 
								 | 
							
								      .configureTestingModule({
							 | 
						||
| 
								 | 
							
								        imports: [BagModule],
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      // Compile everything in BagModule
							 | 
						||
| 
								 | 
							
								      .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should create a component with inline template', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(Child1Component);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('Child');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should create a component with external template', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(ExternalTemplateComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('from external template');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should allow changing members of the component', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(MyIfComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('MyIf()');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.componentInstance.showMore = true;
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('MyIf(More)');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should create a nested component bound to inputs/outputs', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(IoParentComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    const heroes = fixture.debugElement.queryAll(By.css('.hero'));
							 | 
						||
| 
								 | 
							
								    expect(heroes.length).toBeGreaterThan(0, 'has heroes');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    const hero = comp.heroes[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    heroes[0].triggerEventHandler('click', null);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const selected = fixture.debugElement.query(By.css('p'));
							 | 
						||
| 
								 | 
							
								    expect(selected).toHaveText(hero.name);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can access the instance variable of an `*ngFor` row', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(IoParentComponent);
							 | 
						||
| 
								 | 
							
								    const comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    const heroEl = fixture.debugElement.query(By.css('.hero')); // first hero
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const ngForRow = heroEl.parent; // Angular's NgForRow wrapper element
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // jasmine.any is instance-of-type test.
							 | 
						||
| 
								 | 
							
								    expect(ngForRow.componentInstance).toEqual(jasmine.any(IoComponent), 'component is IoComp');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const hero = ngForRow.context['$implicit']; // the hero object
							 | 
						||
| 
								 | 
							
								    expect(hero.name).toBe(comp.heroes[0].name, '1st hero\'s name');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #docregion ButtonComp
							 | 
						||
| 
								 | 
							
								  it('should support clicking a button', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(ButtonComponent);
							 | 
						||
| 
								 | 
							
								    const btn  = fixture.debugElement.query(By.css('button'));
							 | 
						||
| 
								 | 
							
								    const span = fixture.debugElement.query(By.css('span')).nativeElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(span.textContent).toMatch(/is off/i, 'before click');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    btn.triggerEventHandler('click', null);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(span.textContent).toMatch(/is on/i, 'after click');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  // #enddocregion ButtonComp
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // ngModel is async so we must wait for it with promise-based `whenStable`
							 | 
						||
| 
								 | 
							
								  it('should support entering text in input box (ngModel)', async(() => {
							 | 
						||
| 
								 | 
							
								    const expectedOrigName = 'John';
							 | 
						||
| 
								 | 
							
								    const expectedNewName = 'Sally';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(InputComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    const input = <HTMLInputElement> fixture.debugElement.query(By.css('input')).nativeElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(comp.name).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								      `At start name should be ${expectedOrigName} `);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // wait until ngModel binds comp.name to input box
							 | 
						||
| 
								 | 
							
								    fixture.whenStable().then(() => {
							 | 
						||
| 
								 | 
							
								      expect(input.value).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								        `After ngModel updates input box, input.value should be ${expectedOrigName} `);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // simulate user entering new name in input
							 | 
						||
| 
								 | 
							
								      input.value = expectedNewName;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // that change doesn't flow to the component immediately
							 | 
						||
| 
								 | 
							
								      expect(comp.name).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								        `comp.name should still be ${expectedOrigName} after value change, before binding happens`);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // dispatch a DOM event so that Angular learns of input value change.
							 | 
						||
| 
								 | 
							
								      // then wait while ngModel pushes input.box value to comp.name
							 | 
						||
| 
								 | 
							
								      input.dispatchEvent(newEvent('input'));
							 | 
						||
| 
								 | 
							
								      return fixture.whenStable();
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      expect(comp.name).toBe(expectedNewName,
							 | 
						||
| 
								 | 
							
								        `After ngModel updates the model, comp.name should be ${expectedNewName} `);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // fakeAsync version of ngModel input test enables sync test style
							 | 
						||
| 
								 | 
							
								  // synchronous `tick` replaces asynchronous promise-base `whenStable`
							 | 
						||
| 
								 | 
							
								  it('should support entering text in input box (ngModel) - fakeAsync', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    const expectedOrigName = 'John';
							 | 
						||
| 
								 | 
							
								    const expectedNewName = 'Sally';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(InputComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const comp =  fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    const input = <HTMLInputElement> fixture.debugElement.query(By.css('input')).nativeElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(comp.name).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								      `At start name should be ${expectedOrigName} `);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // wait until ngModel binds comp.name to input box
							 | 
						||
| 
								 | 
							
								    tick();
							 | 
						||
| 
								 | 
							
								    expect(input.value).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								      `After ngModel updates input box, input.value should be ${expectedOrigName} `);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // simulate user entering new name in input
							 | 
						||
| 
								 | 
							
								    input.value = expectedNewName;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // that change doesn't flow to the component immediately
							 | 
						||
| 
								 | 
							
								    expect(comp.name).toBe(expectedOrigName,
							 | 
						||
| 
								 | 
							
								      `comp.name should still be ${expectedOrigName} after value change, before binding happens`);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dispatch a DOM event so that Angular learns of input value change.
							 | 
						||
| 
								 | 
							
								    // then wait a tick while ngModel pushes input.box value to comp.name
							 | 
						||
| 
								 | 
							
								    input.dispatchEvent(newEvent('input'));
							 | 
						||
| 
								 | 
							
								    tick();
							 | 
						||
| 
								 | 
							
								    expect(comp.name).toBe(expectedNewName,
							 | 
						||
| 
								 | 
							
								      `After ngModel updates the model, comp.name should be ${expectedNewName} `);
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #docregion ReversePipeComp
							 | 
						||
| 
								 | 
							
								  it('ReversePipeComp should reverse the input text', fakeAsync(() => {
							 | 
						||
| 
								 | 
							
								    const inputText = 'the quick brown fox.';
							 | 
						||
| 
								 | 
							
								    const expectedText = '.xof nworb kciuq eht';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(ReversePipeComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const comp =  fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
							 | 
						||
| 
								 | 
							
								    const span =  fixture.debugElement.query(By.css('span')).nativeElement  as HTMLElement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // simulate user entering new name in input
							 | 
						||
| 
								 | 
							
								    input.value = inputText;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dispatch a DOM event so that Angular learns of input value change.
							 | 
						||
| 
								 | 
							
								    // then wait a tick while ngModel pushes input.box value to comp.text
							 | 
						||
| 
								 | 
							
								    // and Angular updates the output span
							 | 
						||
| 
								 | 
							
								    input.dispatchEvent(newEvent('input'));
							 | 
						||
| 
								 | 
							
								    tick();
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(span.textContent).toBe(expectedText, 'output span');
							 | 
						||
| 
								 | 
							
								    expect(comp.text).toBe(inputText, 'component.text');
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								  // #enddocregion ReversePipeComp
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Use this technique to find attached directives of any kind
							 | 
						||
| 
								 | 
							
								  it('can examine attached directives and listeners', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(InputComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const inputEl = fixture.debugElement.query(By.css('input'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(inputEl.providerTokens).toContain(NgModel, 'NgModel directive');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const ngControl = inputEl.injector.get(NgControl);
							 | 
						||
| 
								 | 
							
								    expect(ngControl).toEqual(jasmine.any(NgControl), 'NgControl directive');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(inputEl.listeners.length).toBeGreaterThan(2, 'several listeners attached');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // #docregion debug-dom-renderer
							 | 
						||
| 
								 | 
							
								  it('DebugDomRender should set attributes, styles, classes, and properties', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(BankAccountParentComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    const comp = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // the only child is debugElement of the BankAccount component
							 | 
						||
| 
								 | 
							
								    const el = fixture.debugElement.children[0];
							 | 
						||
| 
								 | 
							
								    const childComp = el.componentInstance as BankAccountComponent;
							 | 
						||
| 
								 | 
							
								    expect(childComp).toEqual(jasmine.any(BankAccountComponent));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.context).toBe(comp, 'context is the parent component');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.attributes['account']).toBe(childComp.id, 'account attribute');
							 | 
						||
| 
								 | 
							
								    expect(el.attributes['bank']).toBe(childComp.bank, 'bank attribute');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.classes['closed']).toBe(true, 'closed class');
							 | 
						||
| 
								 | 
							
								    expect(el.classes['open']).toBe(false, 'open class');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.properties['customProperty']).toBe(true, 'customProperty');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.styles['color']).toBe(comp.color, 'color style');
							 | 
						||
| 
								 | 
							
								    expect(el.styles['width']).toBe(comp.width + 'px', 'width style');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  // #enddocregion debug-dom-renderer
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('TestBed Component Overrides:', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should override ChildComp\'s template', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [Child1Component],
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(Child1Component, {
							 | 
						||
| 
								 | 
							
								      set: { template: '<span>Fake</span>' }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(Child1Component);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('Fake');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should override TestProvidersComp\'s FancyService provider', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [TestProvidersComponent],
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(TestProvidersComponent, {
							 | 
						||
| 
								 | 
							
								      remove: { providers: [FancyService]},
							 | 
						||
| 
								 | 
							
								      add:    { providers: [{ provide: FancyService, useClass: FakeFancyService }] },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Or replace them all (this component has only one provider)
							 | 
						||
| 
								 | 
							
								      // set:    { providers: [{ provide: FancyService, useClass: FakeFancyService }] },
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(TestProvidersComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('injected value: faked value', 'text');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Explore the providerTokens
							 | 
						||
| 
								 | 
							
								    const tokens = fixture.debugElement.providerTokens;
							 | 
						||
| 
								 | 
							
								    expect(tokens).toContain(fixture.componentInstance.constructor, 'component ctor');
							 | 
						||
| 
								 | 
							
								    expect(tokens).toContain(TestProvidersComponent, 'TestProvidersComp');
							 | 
						||
| 
								 | 
							
								    expect(tokens).toContain(FancyService, 'FancyService');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should override TestViewProvidersComp\'s FancyService viewProvider', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [TestViewProvidersComponent],
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(TestViewProvidersComponent, {
							 | 
						||
| 
								 | 
							
								      // remove: { viewProviders: [FancyService]},
							 | 
						||
| 
								 | 
							
								      // add:    { viewProviders: [{ provide: FancyService, useClass: FakeFancyService }] },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // Or replace them all (this component has only one viewProvider)
							 | 
						||
| 
								 | 
							
								      set:    { viewProviders: [{ provide: FancyService, useClass: FakeFancyService }] },
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(TestViewProvidersComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('injected value: faked value');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('injected provider should not be same as component\'s provider', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TestComponent is parent of TestProvidersComponent
							 | 
						||
| 
								 | 
							
								    @Component({ template: '<my-service-comp></my-service-comp>' })
							 | 
						||
| 
								 | 
							
								    class TestComponent {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // 3 levels of FancyService provider: module, TestCompomponent, TestProvidersComponent
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [TestComponent, TestProvidersComponent],
							 | 
						||
| 
								 | 
							
								      providers:    [FancyService]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(TestComponent, {
							 | 
						||
| 
								 | 
							
								      set: { providers: [{ provide: FancyService, useValue: {} }] }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(TestProvidersComponent, {
							 | 
						||
| 
								 | 
							
								      set: { providers: [{ provide: FancyService, useClass: FakeFancyService }] }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(TestComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let testBedProvider: FancyService;
							 | 
						||
| 
								 | 
							
								    let tcProvider: {};
							 | 
						||
| 
								 | 
							
								    let tpcProvider: FakeFancyService;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // `inject` uses TestBed's injector
							 | 
						||
| 
								 | 
							
								    inject([FancyService], (s: FancyService) => testBedProvider = s)();
							 | 
						||
| 
								 | 
							
								    tcProvider = fixture.debugElement.injector.get(FancyService);
							 | 
						||
| 
								 | 
							
								    tpcProvider = fixture.debugElement.children[0].injector.get(FancyService);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(testBedProvider).not.toBe(tcProvider, 'testBed/tc not same providers');
							 | 
						||
| 
								 | 
							
								    expect(testBedProvider).not.toBe(tpcProvider, 'testBed/tpc not same providers');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(testBedProvider instanceof FancyService).toBe(true, 'testBedProvider is FancyService');
							 | 
						||
| 
								 | 
							
								    expect(tcProvider).toEqual({}, 'tcProvider is {}');
							 | 
						||
| 
								 | 
							
								    expect(tpcProvider instanceof FakeFancyService).toBe(true, 'tpcProvider is FakeFancyService');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('can access template local variables as references', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ShellComponent, NeedsContentComponent, Child1Component, Child2Component, Child3Component],
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .overrideComponent(ShellComponent, {
							 | 
						||
| 
								 | 
							
								      set: {
							 | 
						||
| 
								 | 
							
								        selector: 'test-shell',
							 | 
						||
| 
								 | 
							
								        template: `
							 | 
						||
| 
								 | 
							
								        <needs-content #nc>
							 | 
						||
| 
								 | 
							
								          <child-1 #content text="My"></child-1>
							 | 
						||
| 
								 | 
							
								          <child-2 #content text="dog"></child-2>
							 | 
						||
| 
								 | 
							
								          <child-2 text="has"></child-2>
							 | 
						||
| 
								 | 
							
								          <child-3 #content text="fleas"></child-3>
							 | 
						||
| 
								 | 
							
								          <div #content>!</div>
							 | 
						||
| 
								 | 
							
								        </needs-content>
							 | 
						||
| 
								 | 
							
								        `
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .createComponent(ShellComponent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // NeedsContentComp is the child of ShellComp
							 | 
						||
| 
								 | 
							
								    const el = fixture.debugElement.children[0];
							 | 
						||
| 
								 | 
							
								    const comp = el.componentInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(comp.children.toArray().length).toBe(4,
							 | 
						||
| 
								 | 
							
								      'three different child components and an ElementRef with #content');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(el.references['nc']).toBe(comp, '#nc reference to component');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // #docregion custom-predicate
							 | 
						||
| 
								 | 
							
								    // Filter for DebugElements with a #content reference
							 | 
						||
| 
								 | 
							
								    const contentRefs = el.queryAll( de => de.references['content']);
							 | 
						||
| 
								 | 
							
								    // #enddocregion custom-predicate
							 | 
						||
| 
								 | 
							
								    expect(contentRefs.length).toBe(4, 'elements w/ a #content reference');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('Nested (one-deep) component override', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ParentComponent, FakeChildComponent]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('ParentComp should use Fake Child component', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(ParentComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('Parent(Fake Child)');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('Nested (two-deep) component override', () => {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      declarations: [ParentComponent, FakeChildWithGrandchildComponent, FakeGrandchildComponent]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents();
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should use Fake Grandchild component', () => {
							 | 
						||
| 
								 | 
							
								    const fixture = TestBed.createComponent(ParentComponent);
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(fixture).toHaveText('Parent(Fake Child(Fake Grandchild))');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('Lifecycle hooks w/ MyIfParentComp', () => {
							 | 
						||
| 
								 | 
							
								  let fixture: ComponentFixture<MyIfParentComponent>;
							 | 
						||
| 
								 | 
							
								  let parent:  MyIfParentComponent;
							 | 
						||
| 
								 | 
							
								  let child:   MyIfChildComponent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach( async(() => {
							 | 
						||
| 
								 | 
							
								    TestBed.configureTestingModule({
							 | 
						||
| 
								 | 
							
								      imports: [FormsModule],
							 | 
						||
| 
								 | 
							
								      declarations: [MyIfChildComponent, MyIfParentComponent]
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .compileComponents().then(() => {
							 | 
						||
| 
								 | 
							
								      fixture = TestBed.createComponent(MyIfParentComponent);
							 | 
						||
| 
								 | 
							
								      parent = fixture.componentInstance;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should instantiate parent component', () => {
							 | 
						||
| 
								 | 
							
								    expect(parent).not.toBeNull('parent component should exist');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('parent component OnInit should NOT be called before first detectChanges()', () => {
							 | 
						||
| 
								 | 
							
								    expect(parent.ngOnInitCalled).toBe(false);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('parent component OnInit should be called after first detectChanges()', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(parent.ngOnInitCalled).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('child component should exist after OnInit', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								    expect(child instanceof MyIfChildComponent).toBe(true, 'should create child');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should have called child component\'s OnInit ', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								    expect(child.ngOnInitCalled).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('child component called OnChanges once', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								    expect(child.ngOnChangesCounter).toBe(1);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('changed parent value flows to child', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    parent.parentValue = 'foo';
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(child.ngOnChangesCounter).toBe(2,
							 | 
						||
| 
								 | 
							
								      'expected 2 changes: initial value and changed value');
							 | 
						||
| 
								 | 
							
								    expect(child.childValue).toBe('foo',
							 | 
						||
| 
								 | 
							
								      'childValue should eq changed parent value');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // must be async test to see child flow to parent
							 | 
						||
| 
								 | 
							
								  it('changed child value flows to parent', async(() => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    child.childValue = 'bar';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      // Wait one JS engine turn!
							 | 
						||
| 
								 | 
							
								      setTimeout(() => resolve(), 0);
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    .then(() => {
							 | 
						||
| 
								 | 
							
								      fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(child.ngOnChangesCounter).toBe(2,
							 | 
						||
| 
								 | 
							
								        'expected 2 changes: initial value and changed value');
							 | 
						||
| 
								 | 
							
								      expect(parent.parentValue).toBe('bar',
							 | 
						||
| 
								 | 
							
								        'parentValue should eq changed parent value');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('clicking "Close Child" triggers child OnDestroy', () => {
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    getChild();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const btn = fixture.debugElement.query(By.css('button'));
							 | 
						||
| 
								 | 
							
								    btn.triggerEventHandler('click', null);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fixture.detectChanges();
							 | 
						||
| 
								 | 
							
								    expect(child.ngOnDestroyCalled).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ////// helpers ///
							 | 
						||
| 
								 | 
							
								  /**
							 | 
						||
| 
								 | 
							
								   * Get the MyIfChildComp from parent; fail w/ good message if cannot.
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								  function getChild() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let childDe: DebugElement; // DebugElement that should hold the MyIfChildComp
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // The Hard Way: requires detailed knowledge of the parent template
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      childDe = fixture.debugElement.children[4].children[0];
							 | 
						||
| 
								 | 
							
								    } catch (err) { /* we'll report the error */ }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // DebugElement.queryAll: if we wanted all of many instances:
							 | 
						||
| 
								 | 
							
								    childDe = fixture.debugElement
							 | 
						||
| 
								 | 
							
								      .queryAll(function (de) { return de.componentInstance instanceof MyIfChildComponent; })[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // WE'LL USE THIS APPROACH !
							 | 
						||
| 
								 | 
							
								    // DebugElement.query: find first instance (if any)
							 | 
						||
| 
								 | 
							
								    childDe = fixture.debugElement
							 | 
						||
| 
								 | 
							
								      .query(function (de) { return de.componentInstance instanceof MyIfChildComponent; });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (childDe && childDe.componentInstance) {
							 | 
						||
| 
								 | 
							
								      child = childDe.componentInstance;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      fail('Unable to find MyIfChildComp within MyIfParentComp');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return child;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////////// Fakes ///////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'child-1',
							 | 
						||
| 
								 | 
							
								  template: `Fake Child`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								class FakeChildComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'child-1',
							 | 
						||
| 
								 | 
							
								  template: `Fake Child(<grandchild-1></grandchild-1>)`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								class FakeChildWithGrandchildComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  selector: 'grandchild-1',
							 | 
						||
| 
								 | 
							
								  template: `Fake Grandchild`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								class FakeGrandchildComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								class FakeFancyService extends FancyService {
							 | 
						||
| 
								 | 
							
								  value: string = 'faked value';
							 | 
						||
| 
								 | 
							
								}
							 |