1
+ // #docplaster
1
2
import {
2
3
async , ComponentFixture , fakeAsync , inject , TestBed , tick
3
4
} from '@angular/core/testing' ;
@@ -7,7 +8,7 @@ import { DebugElement } from '@angular/core';
7
8
8
9
import {
9
10
addMatchers , newEvent ,
10
- ActivatedRoute , FakeActivatedRoute , Router , FakeRouter
11
+ ActivatedRoute , ActivatedRouteStub , Router , RouterStub
11
12
} from '../../testing' ;
12
13
13
14
import { HEROES , FakeHeroService } from '../model/testing' ;
@@ -18,7 +19,7 @@ import { HeroDetailService } from './hero-detail.service';
18
19
import { Hero , HeroService } from '../model' ;
19
20
20
21
////// Testing Vars //////
21
- let activatedRoute : FakeActivatedRoute ;
22
+ let activatedRoute : ActivatedRouteStub ;
22
23
let comp : HeroDetailComponent ;
23
24
let fixture : ComponentFixture < HeroDetailComponent > ;
24
25
let page : Page ;
@@ -29,7 +30,7 @@ describe('HeroDetailComponent', () => {
29
30
30
31
beforeEach ( async ( ( ) => {
31
32
addMatchers ( ) ;
32
- activatedRoute = new FakeActivatedRoute ( ) ;
33
+ activatedRoute = new ActivatedRouteStub ( ) ;
33
34
34
35
TestBed . configureTestingModule ( {
35
36
imports : [ HeroModule ] ,
@@ -40,12 +41,13 @@ describe('HeroDetailComponent', () => {
40
41
providers : [
41
42
{ provide : ActivatedRoute , useValue : activatedRoute } ,
42
43
{ provide : HeroService , useClass : FakeHeroService } ,
43
- { provide : Router , useClass : FakeRouter } ,
44
+ { provide : Router , useClass : RouterStub } ,
44
45
]
45
46
} )
46
47
. compileComponents ( ) ;
47
48
} ) ) ;
48
49
50
+ // #docregion route-good-id
49
51
describe ( 'when navigate to hero id=' + HEROES [ 0 ] . id , ( ) => {
50
52
let expectedHero : Hero ;
51
53
@@ -55,51 +57,53 @@ describe('HeroDetailComponent', () => {
55
57
createComponent ( ) ;
56
58
} ) ) ;
57
59
60
+ // #docregion selected-tests
58
61
it ( 'should display that hero\'s name' , ( ) => {
59
62
expect ( page . nameDisplay . textContent ) . toBe ( expectedHero . name ) ;
60
63
} ) ;
64
+ // #enddocregion route-good-id
61
65
62
66
it ( 'should navigate when click cancel' , ( ) => {
63
67
page . cancelBtn . triggerEventHandler ( 'click' , null ) ;
64
68
expect ( page . navSpy . calls . any ( ) ) . toBe ( true , 'router.navigate called' ) ;
65
69
} ) ;
66
70
67
- it ( 'should save when click save' , ( ) => {
71
+ it ( 'should save when click save but not navigate immediately ' , ( ) => {
68
72
page . saveBtn . triggerEventHandler ( 'click' , null ) ;
69
73
expect ( page . saveSpy . calls . any ( ) ) . toBe ( true , 'HeroDetailService.save called' ) ;
74
+ expect ( page . navSpy . calls . any ( ) ) . toBe ( false , 'router.navigate not called' ) ;
70
75
} ) ;
71
76
72
- it ( 'should navigate when click click save resolves' , fakeAsync ( ( ) => {
77
+ it ( 'should navigate when click save and save resolves' , fakeAsync ( ( ) => {
73
78
page . saveBtn . triggerEventHandler ( 'click' , null ) ;
74
- tick ( ) ; // waits for async save to "complete" before navigating
79
+ tick ( ) ; // wait for async save to "complete" before navigating
75
80
expect ( page . navSpy . calls . any ( ) ) . toBe ( true , 'router.navigate called' ) ;
76
81
} ) ) ;
77
82
78
-
79
83
// #docregion title-case-pipe
80
- it ( 'should convert original hero name to Title Case' , ( ) => {
81
- expect ( page . nameDisplay . textContent ) . toBe ( comp . hero . name ) ;
82
- } ) ;
83
- // #enddocregion title-case-pipe
84
-
85
84
it ( 'should convert hero name to Title Case' , fakeAsync ( ( ) => {
86
85
const inputName = 'quick BROWN fox' ;
87
- const expectedName = 'Quick Brown Fox' ;
86
+ const titleCaseName = 'Quick Brown Fox' ;
88
87
89
- // simulate user entering new name in input
88
+ // simulate user entering new name into the input box
90
89
page . nameInput . value = inputName ;
91
90
92
91
// dispatch a DOM event so that Angular learns of input value change.
93
- // detectChanges() makes ngModel push input value to component property
94
- // and Angular updates the output span
95
92
page . nameInput . dispatchEvent ( newEvent ( 'input' ) ) ;
93
+
94
+ // detectChanges() makes [(ngModel)] push input value to component property
95
+ // and Angular updates the output span through the title pipe
96
96
fixture . detectChanges ( ) ;
97
- expect ( page . nameDisplay . textContent ) . toBe ( expectedName , 'hero name display' ) ;
98
- expect ( comp . hero . name ) . toBe ( inputName , 'comp.hero.name' ) ;
99
- } ) ) ;
100
97
98
+ expect ( page . nameDisplay . textContent ) . toBe ( titleCaseName ) ;
99
+ } ) ) ;
100
+ // #enddocregion title-case-pipe
101
+ // #enddocregion selected-tests
102
+ // #docregion route-good-id
101
103
} ) ;
104
+ // #enddocregion route-good-id
102
105
106
+ // #docregion route-no-id
103
107
describe ( 'when navigate with no hero id' , ( ) => {
104
108
beforeEach ( async ( createComponent ) ) ;
105
109
@@ -111,7 +115,9 @@ describe('HeroDetailComponent', () => {
111
115
expect ( page . nameDisplay . textContent ) . toBe ( '' ) ;
112
116
} ) ;
113
117
} ) ;
118
+ // #enddocregion route-no-id
114
119
120
+ // #docregion route-bad-id
115
121
describe ( 'when navigate to non-existant hero id' , ( ) => {
116
122
beforeEach ( async ( ( ) => {
117
123
activatedRoute . testParams = { id : 99999 } ;
@@ -123,6 +129,7 @@ describe('HeroDetailComponent', () => {
123
129
expect ( page . navSpy . calls . any ( ) ) . toBe ( true , 'router.navigate called' ) ;
124
130
} ) ;
125
131
} ) ;
132
+ // #enddocregion route-bad-id
126
133
127
134
///////////////////////////
128
135
@@ -145,22 +152,24 @@ describe('HeroDetailComponent', () => {
145
152
146
153
/////////// Helpers /////
147
154
155
+ // #docregion create-component
148
156
/** Create the HeroDetailComponent, initialize it, set test variables */
149
157
function createComponent ( ) {
150
158
fixture = TestBed . createComponent ( HeroDetailComponent ) ;
151
159
comp = fixture . componentInstance ;
152
160
page = new Page ( ) ;
153
161
154
- // change detection triggers ngOnInit which gets a hero
162
+ // 1st change detection triggers ngOnInit which gets a hero
155
163
fixture . detectChanges ( ) ;
156
164
return fixture . whenStable ( ) . then ( ( ) => {
157
- // got the hero and updated component
158
- // change detection updates the view
165
+ // 2nd change detection displays the async-fetched hero
159
166
fixture . detectChanges ( ) ;
160
167
page . addPageElements ( ) ;
161
168
} ) ;
162
169
}
170
+ // #enddocregion create-component
163
171
172
+ // #docregion page
164
173
class Page {
165
174
gotoSpy : jasmine . Spy ;
166
175
navSpy : jasmine . Spy ;
@@ -173,24 +182,24 @@ class Page {
173
182
174
183
constructor ( ) {
175
184
// Use component's injector to see the services it injected.
176
- let compInjector = fixture . debugElement . injector ;
177
- let hds = compInjector . get ( HeroDetailService ) ;
178
- let router = compInjector . get ( Router ) ;
179
- this . gotoSpy = spyOn ( comp , 'gotoList' ) . and . callThrough ( ) ;
180
- this . saveSpy = spyOn ( hds , 'saveHero' ) . and . callThrough ( ) ;
181
- this . navSpy = spyOn ( router , 'navigate' ) . and . callThrough ( ) ;
185
+ const compInjector = fixture . debugElement . injector ;
186
+ const hds = compInjector . get ( HeroDetailService ) ;
187
+ const router = compInjector . get ( Router ) ;
188
+ this . gotoSpy = spyOn ( comp , 'gotoList' ) . and . callThrough ( ) ;
189
+ this . saveSpy = spyOn ( hds , 'saveHero' ) . and . callThrough ( ) ;
190
+ this . navSpy = spyOn ( router , 'navigate' ) . and . callThrough ( ) ;
182
191
}
183
192
184
- /** Add page elements after page initializes */
193
+ /** Add page elements after hero arrives */
185
194
addPageElements ( ) {
186
195
if ( comp . hero ) {
187
- // have a hero so these DOM elements can be reached
188
- let buttons = fixture . debugElement . queryAll ( By . css ( 'button' ) ) ;
196
+ // have a hero so these elements are now in the DOM
197
+ const buttons = fixture . debugElement . queryAll ( By . css ( 'button' ) ) ;
189
198
this . saveBtn = buttons [ 0 ] ;
190
199
this . cancelBtn = buttons [ 1 ] ;
191
200
this . nameDisplay = fixture . debugElement . query ( By . css ( 'span' ) ) . nativeElement ;
192
201
this . nameInput = fixture . debugElement . query ( By . css ( 'input' ) ) . nativeElement ;
193
202
}
194
203
}
195
204
}
196
-
205
+ // #enddocregion page
0 commit comments