Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 11160f0

Browse files
filipesilvawardbell
authored andcommitted
chore(testing): add testing files to examples
1 parent c1ea652 commit 11160f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2488
-253
lines changed

public/docs/_examples/structural-directives/ts/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
1818
<script>
1919
System.config({
20-
packages: {
20+
packages: {
2121
app: {
2222
format: 'register',
2323
defaultExtension: 'js'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/*.js
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// #docplaster
2+
// #docregion it
3+
it('true is true', () => expect(true).toEqual(true));
4+
// #enddocregion it
5+
6+
// #docregion describe
7+
describe('1st tests', () => {
8+
9+
it('true is true', () => expect(true).toEqual(true));
10+
11+
// #enddocregion describe
12+
// #docregion another-test
13+
it('null is not the same thing as undefined',
14+
() => expect(null).not.toEqual(undefined)
15+
);
16+
// #enddocregion another-test
17+
18+
// #docregion describe
19+
});
20+
// #enddocregion describe
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {Hero} from './hero';
2+
import {HEROES} from './mock-heroes';
3+
4+
let delay = 1000; // ms delay in return of data
5+
6+
export class BackendService {
7+
8+
fetchAllHeroesAsync(): Promise<Hero[]> {
9+
return new Promise((resolve, reject) => {
10+
// simulate latency by resolving promise after a delay
11+
setTimeout(() => resolve(HEROES.map(h => h.clone())), delay)
12+
})
13+
}
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import {bootstrap} from 'angular2/platform/browser';
2+
3+
// Application root component
4+
import {HeroesComponent} from './heroes.component';
5+
6+
// Application-wide "injectables""
7+
import {BackendService} from './backend.service';
8+
import {HeroService} from './hero.service';
9+
import {User} from './user';
10+
11+
bootstrap(HeroesComponent, [BackendService, HeroService, User]);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @Injectable is a placeholder decorator
2+
// whose sole purpose is to trigger the TS compiler to
3+
// generate the metadata that Angular DI needs for injection.
4+
//
5+
// Metadata generation happens IFF the class has a decorator ... any decorator
6+
// See the `"emitDecoratorMetadata": true` flag in tsconfig.json
7+
//
8+
// For Angular-agnostic classes we can avoid importing from Angular
9+
// and get the metadata generation side-effect
10+
// by creating our own @Injectable decorator
11+
12+
// for the hip Functional Programmer:
13+
export const Injectable = () => (cls:any) => cls;
14+
15+
// for everyone else, this is the same thing
16+
//export function Injectable() { return (cls:any) => cls; }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.hero-detail div {padding:0.2em;}
2+
.hero-detail div input {position: absolute; left:9em; }
3+
.hero-id {position: absolute; left:7.5em; }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!-- #docregion -->
2+
<div class="hero-detail">
3+
<!-- #docregion pipe-usage -->
4+
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
5+
<!-- #enddocregion pipe-usage -->
6+
<div>
7+
<button (click)="onDelete()" [disabled]="!hero">Delete</button>
8+
<button (click)="onUpdate()" [disabled]="!hero">Update</button>
9+
</div>
10+
<div>
11+
<label>Id: </label><span class="hero-id">{{hero.id}}</span></div>
12+
<div>
13+
<label>Name: </label>
14+
<input [(ngModel)]="hero.name" placeholder="name">
15+
</div>
16+
<div>
17+
<label>Power: </label>
18+
<input [(ngModel)]="hero.power" placeholder="super power">
19+
</div>
20+
<div>
21+
<label>Alter Ego: </label>
22+
<input [(ngModel)]="hero.alterEgo" placeholder="alter ego">
23+
</div>
24+
</div>
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
///// Boiler Plate ////
2+
import {bind, By, Component, Directive, EventEmitter, FORM_DIRECTIVES} from 'angular2/angular2';
3+
4+
// Angular 2 Test Bed
5+
import {
6+
beforeEachProviders, inject, injectAsync, RootTestComponent as RTC,
7+
beforeEach, ddescribe, xdescribe, describe, expect, iit, it, xit // Jasmine wrappers
8+
} from 'angular2/testing';
9+
10+
import {dispatchEvent, DoneFn, injectTcb, tick} from '../test-helpers/test-helpers';
11+
12+
///// Testing this component ////
13+
import {HeroDetailComponent} from './hero-detail.component';
14+
import {Hero} from './hero';
15+
16+
describe('HeroDetailComponent', () => {
17+
18+
/////////// Component Tests without DOM interaction /////////////
19+
describe('(No DOM)', () => {
20+
it('can be created', () => {
21+
let hdc = new HeroDetailComponent();
22+
expect(hdc instanceof HeroDetailComponent).toEqual(true); // proof of life
23+
});
24+
25+
it('onDelete method should raise delete event', (done: DoneFn) => {
26+
let hdc = new HeroDetailComponent();
27+
28+
// Listen for the HeroComponent.delete EventEmitter's event
29+
hdc.delete.toRx().subscribe(() => {
30+
console.log('HeroComponent.delete event raised');
31+
done(); // it must have worked
32+
}, (error: any) => { fail(error); done() });
33+
34+
hdc.onDelete();
35+
});
36+
37+
// Disable until toPromise() works again
38+
xit('onDelete method should raise delete event (w/ promise)', (done: DoneFn) => {
39+
40+
let hdc = new HeroDetailComponent();
41+
42+
// Listen for the HeroComponent.delete EventEmitter's event
43+
let p = hdc.delete.toRx()
44+
.toPromise()
45+
.then(() => {
46+
console.log('HeroComponent.delete event raised in promise');
47+
})
48+
.then(done, done.fail);
49+
50+
hdc.delete.toRx()
51+
.subscribe(() => {
52+
console.log('HeroComponent.delete event raised in subscription')
53+
});
54+
55+
hdc.onDelete();
56+
57+
// toPromise() does not fulfill until emitter is completed by `return()`
58+
hdc.delete.return();
59+
});
60+
61+
it('onUpdate method should modify hero', () => {
62+
let hdc = new HeroDetailComponent();
63+
hdc.hero = new Hero(42, 'Cat Woman');
64+
let origNameLength = hdc.hero.name.length;
65+
66+
hdc.onUpdate();
67+
expect(hdc.hero.name.length).toBeGreaterThan(origNameLength);
68+
});
69+
});
70+
71+
72+
/////////// Component tests that check the DOM /////////////
73+
describe('(DOM)', () => {
74+
// Disable until toPromise() works again
75+
xit('Delete button should raise delete event', injectTcb(tcb => {
76+
77+
// We only care about the button
78+
let template = '<button (click)="onDelete()">Delete</button>';
79+
80+
return tcb
81+
.overrideTemplate(HeroDetailComponent, template)
82+
.createAsync(HeroDetailComponent)
83+
.then((rootTC: RTC) => {
84+
let hdc: HeroDetailComponent = rootTC.debugElement.componentInstance;
85+
86+
// // USE PROMISE WRAPPING AN OBSERVABLE UNTIL can get `toPromise` working again
87+
// let p = new Promise<Hero>((resolve) => {
88+
// // Listen for the HeroComponent.delete EventEmitter's event with observable
89+
// hdc.delete.toRx().subscribe((hero: Hero) => {
90+
// console.log('Observable heard HeroComponent.delete event raised');
91+
// resolve(hero);
92+
// });
93+
// })
94+
95+
//Listen for the HeroComponent.delete EventEmitter's event with promise
96+
let p = <Promise<Hero>> hdc.delete.toRx().toPromise()
97+
.then((hero:Hero) => {
98+
console.log('Promise heard HeroComponent.delete event raised');
99+
});
100+
101+
// trigger the 'click' event on the HeroDetailComponent delete button
102+
let el = rootTC.debugElement.query(By.css('button'));
103+
el.triggerEventHandler('click', null);
104+
105+
// toPromise() does not fulfill until emitter is completed by `return()`
106+
hdc.delete.return();
107+
108+
return p;
109+
});
110+
111+
}));
112+
113+
it('Update button should modify hero', injectTcb(tcb => {
114+
115+
let template =
116+
`<div>
117+
<button id="update" (click)="onUpdate()" [disabled]="!hero">Update</button>
118+
<input [(ngModel)]="hero.name"/>
119+
</div>`
120+
121+
return tcb
122+
.overrideTemplate(HeroDetailComponent, template)
123+
.createAsync(HeroDetailComponent)
124+
.then((rootTC: RTC) => {
125+
126+
let hdc: HeroDetailComponent = rootTC.debugElement.componentInstance;
127+
hdc.hero = new Hero(42, 'Cat Woman');
128+
let origNameLength = hdc.hero.name.length;
129+
130+
// trigger the 'click' event on the HeroDetailComponent update button
131+
rootTC.debugElement.query(By.css('#update'))
132+
.triggerEventHandler('click', null);
133+
134+
expect(hdc.hero.name.length).toBeGreaterThan(origNameLength);
135+
});
136+
}));
137+
138+
it('Entering hero name in textbox changes hero', injectTcb(tcb => {
139+
140+
let hdc: HeroDetailComponent
141+
let template = `<input [(ngModel)]="hero.name"/>`
142+
143+
return tcb
144+
.overrideTemplate(HeroDetailComponent, template)
145+
.createAsync(HeroDetailComponent)
146+
.then((rootTC: RTC) => {
147+
148+
hdc = rootTC.debugElement.componentInstance;
149+
150+
hdc.hero = new Hero(42, 'Cat Woman');
151+
rootTC.detectChanges();
152+
153+
// get the HTML element and change its value in the DOM
154+
var input = rootTC.debugElement.query(By.css('input')).nativeElement;
155+
input.value = "Dog Man"
156+
dispatchEvent(input, 'change'); // event triggers Ng to update model
157+
158+
rootTC.detectChanges();
159+
// model update hasn't happened yet, despite `detectChanges`
160+
expect(hdc.hero.name).toEqual('Cat Woman');
161+
162+
})
163+
.then(tick) // must wait a tick for the model update
164+
.then(() => {
165+
expect(hdc.hero.name).toEqual('Dog Man');
166+
});
167+
}));
168+
169+
// Simulates ...
170+
// 1. change a hero
171+
// 2. select a different hero
172+
// 3 re-select the first hero
173+
// 4. confirm that the change is preserved in HTML
174+
// Reveals 2-way binding bug in alpha-36, fixed in pull #3715 for alpha-37
175+
176+
it('toggling heroes after modifying name preserves the change on screen', injectTcb(tcb => {
177+
178+
let hdc: HeroDetailComponent;
179+
let hero1 = new Hero(1, 'Cat Woman');
180+
let hero2 = new Hero(2, 'Goat Boy');
181+
let input: HTMLInputElement;
182+
let rootTC: RTC;
183+
let template = `{{hero.id}} - <input [(ngModel)]="hero.name"/>`
184+
185+
return tcb
186+
.overrideTemplate(HeroDetailComponent, template)
187+
.createAsync(HeroDetailComponent)
188+
.then((rtc: RTC) => {
189+
rootTC = rtc;
190+
hdc = rootTC.debugElement.componentInstance;
191+
192+
hdc.hero = hero1; // start with hero1
193+
rootTC.detectChanges();
194+
195+
// get the HTML element and change its value in the DOM
196+
input = rootTC.debugElement.query(By.css('input')).nativeElement;
197+
input.value = "Dog Man"
198+
dispatchEvent(input, 'change'); // event triggers Ng to update model
199+
})
200+
.then(tick) // must wait a tick for the model update
201+
.then(() => {
202+
expect(hdc.hero.name).toEqual('Dog Man');
203+
204+
hdc.hero = hero2 // switch to hero2
205+
rootTC.detectChanges();
206+
207+
hdc.hero = hero1 // switch back to hero1
208+
rootTC.detectChanges();
209+
210+
// model value will be the same changed value (of course)
211+
expect(hdc.hero.name).toEqual('Dog Man');
212+
213+
// the view should reflect the same changed value
214+
expect(input.value).toEqual('Dog Man');
215+
});
216+
}));
217+
});
218+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {Component, Directive, EventEmitter , ElementRef} from 'angular2/core';
2+
3+
import {Hero} from './hero';
4+
import {InitCapsPipe} from './init-caps-pipe';
5+
6+
@Directive({selector: 'button'})
7+
class DecoratorDirective {
8+
constructor(el: ElementRef){
9+
console.log(el)
10+
}
11+
}
12+
@Component({
13+
selector: 'my-hero-detail',
14+
templateUrl: 'app/hero-detail.component.html',
15+
inputs: ['hero', 'userName'], // inputs
16+
outputs: ['delete'], // outputs
17+
directives: [DecoratorDirective],
18+
styleUrls: ['app/hero-detail.component.css'],
19+
pipes: [InitCapsPipe]
20+
})
21+
export class HeroDetailComponent {
22+
23+
hero: Hero;
24+
25+
delete = new EventEmitter();
26+
27+
onDelete() { this.delete.next(this.hero) }
28+
29+
onUpdate() {
30+
if (this.hero) {
31+
this.hero.name += 'x';
32+
}
33+
}
34+
userName: string;
35+
}

0 commit comments

Comments
 (0)