Skip to content

Commit 5488fec

Browse files
committed
docs(architecture/ts): proofread
- e2e tests now also cover the tax calculator. - Dart app updated to match TS (it had no sales tax calculator). - TS sample source cleanup (e.g. removed many unnecessary `docregions`). - Prose updated to include @kwalrath's revisions from a while ago, with some of my edits as well. Contributes to angular#1598 and angular#1508.
1 parent 3855d75 commit 5488fec

11 files changed

+521
-456
lines changed
+108-58
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,113 @@
11
/// <reference path='../_protractor/e2e.d.ts' />
22
'use strict';
3-
describe('Architecture', function () {
4-
5-
let title = 'Hero List';
6-
7-
beforeAll(function () {
8-
browser.get('');
9-
});
10-
11-
function itReset(name: string, func: () => any) {
12-
it(name, function() {
13-
browser.get('').then(func);
14-
});
15-
}
16-
17-
it(`should display correct title: ${title}`, function () {
18-
expect(element(by.css('h2')).getText()).toEqual(title);
19-
});
20-
21-
it('should display correct detail after selection', function() {
22-
let detailView = element(by.css('hero-detail'));
23-
expect(detailView.isPresent()).toBe(false);
24-
// select the 2nd element
25-
let selectEle = element.all(by.css('hero-list > div')).get(1);
26-
selectEle.click().then(function() {
27-
return selectEle.getText();
28-
}).then(function(selectedHeroName) {
29-
// works but too specific if we change the app
30-
// expect(selectedHeroName).toEqual('Mr. Nice');
31-
expect(detailView.isDisplayed()).toBe(true);
32-
let detailTitleEle = element(by.css('hero-detail > h4'));
33-
expect(detailTitleEle.getText()).toContain(selectedHeroName);
34-
});
35-
});
36-
37-
itReset('should display correct detail after modification', function() {
38-
let detailView = element(by.css('hero-detail'));
39-
expect(detailView.isPresent()).toBe(false);
40-
// select the 2nd element
41-
let selectEle = element.all(by.css('hero-list > div')).get(1);
42-
selectEle.click().then(function () {
43-
return selectEle.getText();
44-
}).then(function (selectedHeroName) {
45-
let detailTitleEle = element(by.css('hero-detail > h4'));
46-
expect(detailTitleEle.getText()).toContain(selectedHeroName);
47-
let heroNameEle = element.all(by.css('hero-detail input')).get(0);
48-
49-
// check that both the initial selected item and the detail title reflect changes
50-
// made to the input box.
51-
// heroNameEle.sendKeys('foo');
52-
sendKeys(heroNameEle, 'foo');
53-
expect(detailTitleEle.getText()).toContain('foo');
54-
expect(selectEle.getText()).toContain('foo');
55-
56-
// getText on an input element always returns null
57-
// http://stackoverflow.com/questions/20310442/how-to-gettext-on-an-input-in-protractor
58-
// expect(heroNameEle.getText()).toEqual(selectedHeroName);
59-
expect(heroNameEle.getAttribute('value')).toEqual(selectedHeroName + 'foo');
60-
});
3+
4+
const nameSuffix = 'X';
5+
type WPromise<T> = webdriver.promise.Promise<T>;
6+
7+
class Hero {
8+
id: number;
9+
name: string;
10+
}
11+
12+
describe('Architecture', () => {
13+
14+
const expectedTitle = 'Architecture of Angular 2';
15+
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
16+
17+
beforeAll(() => browser.get(''));
18+
19+
it(`has title '${expectedTitle}'`, () => {
20+
expect(browser.getTitle()).toEqual(expectedTitle);
21+
});
22+
23+
it(`has h2 '${expectedH2}'`, () => {
24+
let h2 = element.all(by.css('h2')).map((elt) => elt.getText());
25+
expect(h2).toEqual(expectedH2);
6126
});
6227

28+
describe('Hero', heroTests);
29+
describe('Salex tax', salesTaxTests);
6330
});
31+
32+
function heroTests() {
33+
34+
const targetHero: Hero = { id: 2, name: 'Mr. Nice' };
35+
36+
it('has the right number of heroes', () => {
37+
let page = getPageElts();
38+
expect(page.heroes.count()).toEqual(3);
39+
});
40+
41+
it('has no hero details initially', function () {
42+
let page = getPageElts();
43+
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
44+
});
45+
46+
it(`selects ${targetHero.name} from hero list`, function () {
47+
let hero = element(by.cssContainingText('li', targetHero.name));
48+
hero.click();
49+
// Nothing specific to expect other than lack of exceptions.
50+
});
51+
52+
it('shows selected hero details', async () => {
53+
let page = getPageElts();
54+
let hero = await heroFromDetail(page.heroDetail);
55+
expect(hero.id).toEqual(targetHero.id);
56+
expect(hero.name).toEqual(targetHero.name);
57+
});
58+
59+
it(`can update hero name`, () => {
60+
addToHeroName(nameSuffix);
61+
// Nothing specific to expect other than lack of exceptions.
62+
});
63+
64+
it(`shows updated hero name in details`, async () => {
65+
let page = getPageElts();
66+
let hero = await heroFromDetail(page.heroDetail);
67+
let newName = targetHero.name + nameSuffix;
68+
expect(hero.id).toEqual(targetHero.id);
69+
expect(hero.name).toEqual(newName);
70+
});
71+
}
72+
73+
function salesTaxTests() {
74+
it('has no sales tax initially', function () {
75+
let page = getPageElts();
76+
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
77+
});
78+
79+
it('shows sales tax', async function () {
80+
let page = getPageElts();
81+
await sendKeys(page.salesTaxAmountInput, '10');
82+
// Note: due to Dart bug USD is shown instead of $
83+
let re = /The sales tax is (\$|USD)1.00/;
84+
expect(page.salesTaxDetail.getText()).toMatch(re);
85+
});
86+
}
87+
88+
// Helper functions
89+
90+
function getPageElts() {
91+
return {
92+
heroes: element.all(by.css('my-app li')),
93+
heroDetail: element(by.css('my-app hero-detail')),
94+
salesTaxAmountInput: element(by.css('my-app sales-tax input')),
95+
salesTaxDetail: element(by.css('my-app sales-tax div'))
96+
};
97+
}
98+
99+
function addToHeroName(text: string): WPromise<void> {
100+
let input = element.all(by.css('input')).first();
101+
return sendKeys(input, text);
102+
}
103+
104+
async function heroFromDetail(detail: protractor.ElementFinder): Promise<Hero> {
105+
// Get hero id from the first <div>
106+
let _id = await detail.all(by.css('div')).first().getText();
107+
// Get name from the h2
108+
let _name = await detail.element(by.css('h4')).getText();
109+
return {
110+
id: +_id.substr(_id.indexOf(' ') + 1),
111+
name: _name.substr(0, _name.lastIndexOf(' '))
112+
};
113+
}

public/docs/_examples/architecture/ts/app/hero-detail.component.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<h4>{{hero.name}} Detail</h4>
33
<div>Id: {{hero.id}}</div>
44
<div>Name:
5-
<!-- #docregion ngModel -->
6-
<input [(ngModel)]="hero.name">
7-
<!-- #enddocregion ngModel -->
5+
<!-- #docregion ngModel -->
6+
<input [(ngModel)]="hero.name">
7+
<!-- #enddocregion ngModel -->
88
</div>
9-
<div>Power:<input [(ngModel)]="hero.power"></div>
9+
<div>Power:<input [(ngModel)]="hero.power"></div>
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
<!--#docregion binding -->
2-
<div>{{hero.name}}</div>
2+
<li>{{hero.name}}</li>
33
<hero-detail [hero]="selectedHero"></hero-detail>
4-
<div (click)="selectHero(hero)"></div>
5-
4+
<li (click)="selectHero(hero)"></li>
65
<!--#enddocregion binding -->
76

87
<!--#docregion structural -->
9-
<div *ngFor="let hero of heroes"></div>
8+
<li *ngFor="let hero of heroes"></li>
109
<hero-detail *ngIf="selectedHero"></hero-detail>
11-
12-
<!--#enddocregion structural -->

public/docs/_examples/architecture/ts/app/hero-list.component.html

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
<h2>Hero List</h2>
33

44
<p><i>Pick a hero from the list</i></p>
5-
<div *ngFor="let hero of heroes" (click)="selectHero(hero)">
6-
{{hero.name}}
7-
</div>
5+
<ul>
6+
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
7+
{{hero.name}}
8+
</li>
9+
</ul>
810

911
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,32 @@
1-
// #docplaster
21
import { Component, OnInit } from '@angular/core';
32

43
import { Hero } from './hero';
54
import { HeroDetailComponent } from './hero-detail.component';
65
import { HeroService } from './hero.service';
76

8-
// #docregion metadata
9-
// #docregion providers
7+
// #docregion metadata, providers
108
@Component({
11-
// #enddocregion providers
9+
// #enddocregion providers
1210
selector: 'hero-list',
1311
templateUrl: 'app/hero-list.component.html',
1412
directives: [HeroDetailComponent],
15-
// #docregion providers
13+
// #docregion providers
1614
providers: [HeroService]
1715
})
18-
// #enddocregion providers
19-
// #enddocregion metadata
20-
/*
21-
// #docregion metadata, providers
22-
export class HeroesComponent { ... }
23-
// #enddocregion metadata, providers
24-
*/
2516
// #docregion class
2617
export class HeroListComponent implements OnInit {
18+
// #enddocregion metadata, providers
2719
heroes: Hero[];
2820
selectedHero: Hero;
2921

30-
// #docregion ctor
22+
// #docregion ctor
3123
constructor(private service: HeroService) { }
32-
// #enddocregion ctor
24+
// #enddocregion ctor
3325

3426
ngOnInit() {
3527
this.heroes = this.service.getHeroes();
3628
}
3729

3830
selectHero(hero: Hero) { this.selectedHero = hero; }
31+
// #docregion metadata, providers
3932
}
40-
// #enddocregion class

public/docs/_examples/architecture/ts/app/hero.service.ts

-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import { Logger } from './logger.service';
99
export class HeroService {
1010
private heroes: Hero[] = [];
1111

12-
// #docregion ctor
1312
constructor(
1413
private backend: BackendService,
1514
private logger: Logger) { }
16-
// #enddocregion ctor
1715

1816
getHeroes() {
1917
this.backend.getAll(Hero).then( (heroes: Hero[]) => {
@@ -23,4 +21,3 @@ export class HeroService {
2321
return this.heroes;
2422
}
2523
}
26-
// #enddocregion class
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// #docregion
21
import { Injectable } from '@angular/core';
32

43
@Injectable()
@@ -8,4 +7,3 @@ export class Logger {
87
error(msg: any) { console.error(msg); }
98
warn(msg: any) { console.warn(msg); }
109
}
11-
// #enddocregion class
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,25 @@
1-
// #docplaster
2-
// #docregion
31
import { Component } from '@angular/core';
42

53
import { SalesTaxService } from './sales-tax.service';
64
import { TaxRateService } from './tax-rate.service';
75

8-
// #docregion metadata
9-
// #docregion providers
106
@Component({
11-
// #enddocregion providers
127
selector: 'sales-tax',
138
template: `
149
<h2>Sales Tax Calculator</h2>
15-
Amount: <input #amountBox (change)="0">
10+
Amount: <input #amountBox (input)="0" type="number">
1611
1712
<div *ngIf="amountBox.value">
1813
The sales tax is
1914
{{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }}
2015
</div>
2116
`,
22-
// #docregion providers
2317
providers: [SalesTaxService, TaxRateService]
2418
})
25-
// #enddocregion providers
26-
// #enddocregion metadata
27-
/*
28-
// #docregion metadata, providers
29-
export class SalesTaxComponent { ... }
30-
// #enddocregion metadata, providers
31-
*/
32-
// #docregion class
3319
export class SalesTaxComponent {
34-
// #docregion ctor
3520
constructor(private salesTaxService: SalesTaxService) { }
36-
// #enddocregion ctor
3721

3822
getTax(value: string | number) {
3923
return this.salesTaxService.getVAT(value);
4024
}
4125
}
42-
// #enddocregion class
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
1-
// #docregion
21
import { Injectable } from '@angular/core';
32

43
import { TaxRateService } from './tax-rate.service';
54

6-
// #docregion class
75
@Injectable()
86
export class SalesTaxService {
97
constructor(private rateService: TaxRateService) { }
8+
109
getVAT(value: string | number) {
11-
let amount: number;
12-
if (typeof value === 'string') {
13-
amount = parseFloat(value);
14-
} else {
15-
amount = value;
16-
}
10+
let amount = (typeof value === 'string') ?
11+
parseFloat(value) : value;
1712
return (amount || 0) * this.rateService.getRate('VAT');
1813
}
1914
}
20-
// #enddocregion class
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
// #docregion
21
import { Injectable } from '@angular/core';
32

4-
// #docregion class
53
@Injectable()
64
export class TaxRateService {
7-
getRate(rateName: string) {return 0.10; } // always 10% everywhere
5+
getRate(rateName: string) { return 0.10; } // 10% everywhere
86
}
9-
// #enddocregion class

0 commit comments

Comments
 (0)