docs: testing guide for CLI (#20697)

- updates tests
- heavy prose revisions
- uses HttpClient (with angular-in-memory-web-api)
- test HeroService using `HttpClientTestingModule`
- scrub away most By.CSS
- fake async observable with `asyncData()`
- extensive Twain work
- different take on retryWhen
- remove app barrels (& systemjs.extras) which troubled plunker/systemjs
- add dummy export const to hero.ts (plunkr/systemjs fails w/o it)
- shrink and re-organize TOC
- add marble testing package and tests
- demonstrate the "no beforeEach()" test coding style
- add section on Http service testing
- prepare for stackblitz
- confirm works in plunker except excluded marble test
- add tests for avoidFile class feature of CodeExampleComponent

PR Close #20697
This commit is contained in:
Ward Bell
2017-10-27 15:48:50 -07:00
committed by Alex Eagle
parent 2a38d93171
commit c30a942329
88 changed files with 4831 additions and 3974 deletions

View File

@ -1,7 +1,9 @@
// #docplaster
import { async, ComponentFixture, TestBed
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { addMatchers, click } from '../../testing';
@ -11,64 +13,96 @@ import { DashboardHeroComponent } from './dashboard-hero.component';
beforeEach( addMatchers );
describe('DashboardHeroComponent class only', () => {
// #docregion class-only
it('raises the selected event when clicked', () => {
const comp = new DashboardHeroComponent();
const hero: Hero = { id: 42, name: 'Test' };
comp.hero = hero;
comp.selected.subscribe(selectedHero => expect(selectedHero).toBe(hero));
comp.click();
});
// #enddocregion class-only
});
describe('DashboardHeroComponent when tested directly', () => {
let comp: DashboardHeroComponent;
let expectedHero: Hero;
let fixture: ComponentFixture<DashboardHeroComponent>;
let heroEl: DebugElement;
let heroDe: DebugElement;
let heroEl: HTMLElement;
// #docregion setup, compile-components
// async beforeEach
beforeEach( async(() => {
beforeEach(async(() => {
// #docregion setup, config-testbed
TestBed.configureTestingModule({
declarations: [ DashboardHeroComponent ],
declarations: [ DashboardHeroComponent ]
})
.compileComponents(); // compile template and css
// #enddocregion setup, config-testbed
.compileComponents();
}));
// #enddocregion compile-components
// synchronous beforeEach
beforeEach(() => {
// #docregion setup
fixture = TestBed.createComponent(DashboardHeroComponent);
comp = fixture.componentInstance;
heroEl = fixture.debugElement.query(By.css('.hero')); // find hero element
// pretend that it was wired to something that supplied a hero
expectedHero = new Hero(42, 'Test Name');
// find the hero's DebugElement and element
heroDe = fixture.debugElement.query(By.css('.hero'));
heroEl = heroDe.nativeElement;
// mock the hero supplied by the parent component
expectedHero = { id: 42, name: 'Test Name' };
// simulate the parent setting the input property with that hero
comp.hero = expectedHero;
fixture.detectChanges(); // trigger initial data binding
// trigger initial data binding
fixture.detectChanges();
// #enddocregion setup
});
// #enddocregion setup
// #docregion name-test
it('should display hero name', () => {
it('should display hero name in uppercase', () => {
const expectedPipedName = expectedHero.name.toUpperCase();
expect(heroEl.nativeElement.textContent).toContain(expectedPipedName);
expect(heroEl.textContent).toContain(expectedPipedName);
});
// #enddocregion name-test
// #docregion click-test
it('should raise selected event when clicked', () => {
it('should raise selected event when clicked (triggerEventHandler)', () => {
let selectedHero: Hero;
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
// #docregion trigger-event-handler
heroEl.triggerEventHandler('click', null);
heroDe.triggerEventHandler('click', null);
// #enddocregion trigger-event-handler
expect(selectedHero).toBe(expectedHero);
});
// #enddocregion click-test
// #docregion click-test-2
it('should raise selected event when clicked', () => {
let selectedHero: Hero;
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
// #docregion click-test-2
it('should raise selected event when clicked (element.click)', () => {
let selectedHero: Hero;
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
heroEl.click();
expect(selectedHero).toBe(expectedHero);
});
// #enddocregion click-test-2
// #docregion click-test-3
it('should raise selected event when clicked (click helper)', () => {
let selectedHero: Hero;
comp.selected.subscribe(hero => selectedHero = hero);
click(heroDe); // click helper with DebugElement
click(heroEl); // click helper with native element
click(heroEl); // triggerEventHandler helper
expect(selectedHero).toBe(expectedHero);
});
// #enddocregion click-test-2
// #enddocregion click-test-3
});
//////////////////
@ -76,28 +110,31 @@ describe('DashboardHeroComponent when tested directly', () => {
describe('DashboardHeroComponent when inside a test host', () => {
let testHost: TestHostComponent;
let fixture: ComponentFixture<TestHostComponent>;
let heroEl: DebugElement;
let heroEl: HTMLElement;
// #docregion test-host-setup
beforeEach( async(() => {
beforeEach(async(() => {
// #docregion test-host-setup
TestBed.configureTestingModule({
declarations: [ DashboardHeroComponent, TestHostComponent ], // declare both
}).compileComponents();
declarations: [ DashboardHeroComponent, TestHostComponent ]
})
// #enddocregion test-host-setup
.compileComponents();
}));
beforeEach(() => {
// #docregion test-host-setup
// create TestHostComponent instead of DashboardHeroComponent
fixture = TestBed.createComponent(TestHostComponent);
testHost = fixture.componentInstance;
heroEl = fixture.debugElement.query(By.css('.hero')); // find hero
heroEl = fixture.nativeElement.querySelector('.hero');
fixture.detectChanges(); // trigger initial data binding
// #enddocregion test-host-setup
});
// #enddocregion test-host-setup
// #docregion test-host-tests
it('should display hero name', () => {
const expectedPipedName = testHost.hero.name.toUpperCase();
expect(heroEl.nativeElement.textContent).toContain(expectedPipedName);
expect(heroEl.textContent).toContain(expectedPipedName);
});
it('should raise selected event when clicked', () => {
@ -114,10 +151,12 @@ import { Component } from '@angular/core';
// #docregion test-host
@Component({
template: `
<dashboard-hero [hero]="hero" (selected)="onSelected($event)"></dashboard-hero>`
<dashboard-hero
[hero]="hero" (selected)="onSelected($event)">
</dashboard-hero>`
})
class TestHostComponent {
hero = new Hero(42, 'Test Name');
hero: Hero = {id: 42, name: 'Test Name' };
selectedHero: Hero;
onSelected(hero: Hero) { this.selectedHero = hero; }
}