219 lines
7.3 KiB
Plaintext
219 lines
7.3 KiB
Plaintext
///// Boiler Plate ////
|
|
import {bind, By, Component, Directive, EventEmitter, FORM_DIRECTIVES} from 'angular2/angular2';
|
|
|
|
// Angular 2 Test Bed
|
|
import {
|
|
beforeEachProviders, inject, injectAsync, RootTestComponent as RTC,
|
|
beforeEach, ddescribe, xdescribe, describe, expect, iit, it, xit // Jasmine wrappers
|
|
} from 'angular2/testing';
|
|
|
|
import {dispatchEvent, DoneFn, injectTcb, tick} from '../test-helpers/test-helpers';
|
|
|
|
///// Testing this component ////
|
|
import {HeroDetailComponent} from './hero-detail.component';
|
|
import {Hero} from './hero';
|
|
|
|
describe('HeroDetailComponent', () => {
|
|
|
|
/////////// Component Tests without DOM interaction /////////////
|
|
describe('(No DOM)', () => {
|
|
it('can be created', () => {
|
|
let hdc = new HeroDetailComponent();
|
|
expect(hdc instanceof HeroDetailComponent).toEqual(true); // proof of life
|
|
});
|
|
|
|
it('onDelete method should raise delete event', (done: DoneFn) => {
|
|
let hdc = new HeroDetailComponent();
|
|
|
|
// Listen for the HeroComponent.delete EventEmitter's event
|
|
hdc.delete.toRx().subscribe(() => {
|
|
console.log('HeroComponent.delete event raised');
|
|
done(); // it must have worked
|
|
}, (error: any) => { fail(error); done() });
|
|
|
|
hdc.onDelete();
|
|
});
|
|
|
|
// Disable until toPromise() works again
|
|
xit('onDelete method should raise delete event (w/ promise)', (done: DoneFn) => {
|
|
|
|
let hdc = new HeroDetailComponent();
|
|
|
|
// Listen for the HeroComponent.delete EventEmitter's event
|
|
let p = hdc.delete.toRx()
|
|
.toPromise()
|
|
.then(() => {
|
|
console.log('HeroComponent.delete event raised in promise');
|
|
})
|
|
.then(done, done.fail);
|
|
|
|
hdc.delete.toRx()
|
|
.subscribe(() => {
|
|
console.log('HeroComponent.delete event raised in subscription')
|
|
});
|
|
|
|
hdc.onDelete();
|
|
|
|
// toPromise() does not fulfill until emitter is completed by `return()`
|
|
hdc.delete.return();
|
|
});
|
|
|
|
it('onUpdate method should modify hero', () => {
|
|
let hdc = new HeroDetailComponent();
|
|
hdc.hero = new Hero(42, 'Cat Woman');
|
|
let origNameLength = hdc.hero.name.length;
|
|
|
|
hdc.onUpdate();
|
|
expect(hdc.hero.name.length).toBeGreaterThan(origNameLength);
|
|
});
|
|
});
|
|
|
|
|
|
/////////// Component tests that check the DOM /////////////
|
|
describe('(DOM)', () => {
|
|
// Disable until toPromise() works again
|
|
xit('Delete button should raise delete event', injectTcb(tcb => {
|
|
|
|
// We only care about the button
|
|
let template = '<button (click)="onDelete()">Delete</button>';
|
|
|
|
return tcb
|
|
.overrideTemplate(HeroDetailComponent, template)
|
|
.createAsync(HeroDetailComponent)
|
|
.then((rootTC: RTC) => {
|
|
let hdc: HeroDetailComponent = rootTC.debugElement.componentInstance;
|
|
|
|
// // USE PROMISE WRAPPING AN OBSERVABLE UNTIL can get `toPromise` working again
|
|
// let p = new Promise<Hero>((resolve) => {
|
|
// // Listen for the HeroComponent.delete EventEmitter's event with observable
|
|
// hdc.delete.toRx().subscribe((hero: Hero) => {
|
|
// console.log('Observable heard HeroComponent.delete event raised');
|
|
// resolve(hero);
|
|
// });
|
|
// })
|
|
|
|
//Listen for the HeroComponent.delete EventEmitter's event with promise
|
|
let p = <Promise<Hero>> hdc.delete.toRx().toPromise()
|
|
.then((hero:Hero) => {
|
|
console.log('Promise heard HeroComponent.delete event raised');
|
|
});
|
|
|
|
// trigger the 'click' event on the HeroDetailComponent delete button
|
|
let el = rootTC.debugElement.query(By.css('button'));
|
|
el.triggerEventHandler('click', null);
|
|
|
|
// toPromise() does not fulfill until emitter is completed by `return()`
|
|
hdc.delete.return();
|
|
|
|
return p;
|
|
});
|
|
|
|
}));
|
|
|
|
it('Update button should modify hero', injectTcb(tcb => {
|
|
|
|
let template =
|
|
`<div>
|
|
<button id="update" (click)="onUpdate()" [disabled]="!hero">Update</button>
|
|
<input [(ngModel)]="hero.name"/>
|
|
</div>`
|
|
|
|
return tcb
|
|
.overrideTemplate(HeroDetailComponent, template)
|
|
.createAsync(HeroDetailComponent)
|
|
.then((rootTC: RTC) => {
|
|
|
|
let hdc: HeroDetailComponent = rootTC.debugElement.componentInstance;
|
|
hdc.hero = new Hero(42, 'Cat Woman');
|
|
let origNameLength = hdc.hero.name.length;
|
|
|
|
// trigger the 'click' event on the HeroDetailComponent update button
|
|
rootTC.debugElement.query(By.css('#update'))
|
|
.triggerEventHandler('click', null);
|
|
|
|
expect(hdc.hero.name.length).toBeGreaterThan(origNameLength);
|
|
});
|
|
}));
|
|
|
|
it('Entering hero name in textbox changes hero', injectTcb(tcb => {
|
|
|
|
let hdc: HeroDetailComponent
|
|
let template = `<input [(ngModel)]="hero.name"/>`
|
|
|
|
return tcb
|
|
.overrideTemplate(HeroDetailComponent, template)
|
|
.createAsync(HeroDetailComponent)
|
|
.then((rootTC: RTC) => {
|
|
|
|
hdc = rootTC.debugElement.componentInstance;
|
|
|
|
hdc.hero = new Hero(42, 'Cat Woman');
|
|
rootTC.detectChanges();
|
|
|
|
// get the HTML element and change its value in the DOM
|
|
var input = rootTC.debugElement.query(By.css('input')).nativeElement;
|
|
input.value = "Dog Man"
|
|
dispatchEvent(input, 'change'); // event triggers Ng to update model
|
|
|
|
rootTC.detectChanges();
|
|
// model update hasn't happened yet, despite `detectChanges`
|
|
expect(hdc.hero.name).toEqual('Cat Woman');
|
|
|
|
})
|
|
.then(tick) // must wait a tick for the model update
|
|
.then(() => {
|
|
expect(hdc.hero.name).toEqual('Dog Man');
|
|
});
|
|
}));
|
|
|
|
// Simulates ...
|
|
// 1. change a hero
|
|
// 2. select a different hero
|
|
// 3 re-select the first hero
|
|
// 4. confirm that the change is preserved in HTML
|
|
// Reveals 2-way binding bug in alpha-36, fixed in pull #3715 for alpha-37
|
|
|
|
it('toggling heroes after modifying name preserves the change on screen', injectTcb(tcb => {
|
|
|
|
let hdc: HeroDetailComponent;
|
|
let hero1 = new Hero(1, 'Cat Woman');
|
|
let hero2 = new Hero(2, 'Goat Boy');
|
|
let input: HTMLInputElement;
|
|
let rootTC: RTC;
|
|
let template = `{{hero.id}} - <input [(ngModel)]="hero.name"/>`
|
|
|
|
return tcb
|
|
.overrideTemplate(HeroDetailComponent, template)
|
|
.createAsync(HeroDetailComponent)
|
|
.then((rtc: RTC) => {
|
|
rootTC = rtc;
|
|
hdc = rootTC.debugElement.componentInstance;
|
|
|
|
hdc.hero = hero1; // start with hero1
|
|
rootTC.detectChanges();
|
|
|
|
// get the HTML element and change its value in the DOM
|
|
input = rootTC.debugElement.query(By.css('input')).nativeElement;
|
|
input.value = "Dog Man"
|
|
dispatchEvent(input, 'change'); // event triggers Ng to update model
|
|
})
|
|
.then(tick) // must wait a tick for the model update
|
|
.then(() => {
|
|
expect(hdc.hero.name).toEqual('Dog Man');
|
|
|
|
hdc.hero = hero2 // switch to hero2
|
|
rootTC.detectChanges();
|
|
|
|
hdc.hero = hero1 // switch back to hero1
|
|
rootTC.detectChanges();
|
|
|
|
// model value will be the same changed value (of course)
|
|
expect(hdc.hero.name).toEqual('Dog Man');
|
|
|
|
// the view should reflect the same changed value
|
|
expect(input.value).toEqual('Dog Man');
|
|
});
|
|
}));
|
|
});
|
|
});
|