Skip to content

Commit 6d2e9c9

Browse files
committed
wip
1 parent 4a8c4f6 commit 6d2e9c9

3 files changed

Lines changed: 311 additions & 3 deletions

File tree

src/app/hero.service.spec.ts

Lines changed: 284 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
import { TestBed, inject } from '@angular/core/testing';
2-
import { HttpClientModule } from '@angular/common/http';
2+
import { HttpClientModule, HttpErrorResponse } from '@angular/common/http';
3+
import { asyncData, asyncError } from '../testing/async-observable-helpers';
34

5+
import { Hero } from './hero';
46
import { HeroService } from './hero.service';
57
import { MessageService } from './message.service';
68

79
describe('HeroService', () => {
10+
let httpClientSpy: {
11+
get: jasmine.Spy,
12+
put: jasmine.Spy,
13+
post: jasmine.Spy,
14+
delete: jasmine.Spy
15+
};
16+
let messageServiceSpy: { add: jasmine.Spy };
17+
let heroService: HeroService;
18+
819
beforeEach(() => {
920
TestBed.configureTestingModule({
1021
providers: [
@@ -15,9 +26,280 @@ describe('HeroService', () => {
1526
HttpClientModule
1627
],
1728
});
29+
30+
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get', 'put', 'post', 'delete']);
31+
messageServiceSpy = jasmine.createSpyObj('MessageService', ['add']);
32+
heroService = new HeroService(<any> httpClientSpy, <any> messageServiceSpy);
1833
});
1934

35+
2036
it('should be created', inject([HeroService], (service: HeroService) => {
21-
expect(service).toBeTruthy();
37+
expect(heroService).toBeTruthy();
2238
}));
39+
40+
41+
describe('#getHeroes', () => {
42+
it('should fetch GET /api/heroes', () => {
43+
httpClientSpy.get.and.returnValue(asyncData([]));
44+
heroService.getHeroes();
45+
expect(httpClientSpy.get.calls.allArgs()).toEqual([['api/heroes']]);
46+
});
47+
48+
describe('when GET /api/heroes returns 200 OK', () => {
49+
const heroes: Hero[] = [{ id: 1, name: 'Aa' }, { id: 2, name: 'Ab' }];
50+
51+
beforeEach(() => {
52+
httpClientSpy.get.and.returnValue(asyncData(heroes));
53+
});
54+
55+
it ('should return expected heroes', () => {
56+
heroService.getHeroes().subscribe(
57+
response => expect(response).toEqual(heroes),
58+
fail
59+
);
60+
});
61+
62+
it ('should add a message to the message service', () => {
63+
heroService.getHeroes().subscribe(
64+
response => expect(messageServiceSpy.add.calls.allArgs()).toEqual([['HeroService: fetched heroes']]),
65+
fail
66+
);
67+
});
68+
});
69+
70+
describe('when GET /api/heroes returns 404 Not Found', () => {
71+
beforeEach(() => {
72+
const errorResponse = new HttpErrorResponse({ status: 404, statusText: 'Not Found' });
73+
httpClientSpy.get.and.returnValue(asyncError(errorResponse));
74+
});
75+
76+
it ('should return an empty list of heroes', () => {
77+
heroService.getHeroes().subscribe(
78+
response => expect(response).toEqual([]),
79+
fail
80+
);
81+
});
82+
83+
it ('should add a message to the message service', () => {
84+
const errorMessage = 'HeroService: getHeroes failed: Http failure response for (unknown url): 404 Not Found';
85+
heroService.getHeroes().subscribe(
86+
response => expect(messageServiceSpy.add.calls.allArgs()).toEqual([[errorMessage]]),
87+
fail
88+
);
89+
});
90+
});
91+
});
92+
93+
describe('#getHero', () => {
94+
it('should fetch GET /api/heroes/{id}', () => {
95+
httpClientSpy.get.and.returnValue(asyncData({}));
96+
heroService.getHero(1);
97+
expect(httpClientSpy.get.calls.allArgs()).toEqual([['api/heroes/1']]);
98+
});
99+
100+
describe('when GET /api/heroes/{id} returns 200 OK', () => {
101+
const hero: Hero = { id: 1, name: 'A' };
102+
103+
beforeEach(() => {
104+
httpClientSpy.get.and.returnValue(asyncData(hero));
105+
});
106+
107+
it ('should return expected hero', () => {
108+
heroService.getHero(1).subscribe(
109+
response => expect(response).toEqual(hero),
110+
fail
111+
);
112+
});
113+
114+
it ('should add a message to the message service', () => {
115+
heroService.getHero(1).subscribe(
116+
response => expect(messageServiceSpy.add.calls.allArgs()).toEqual([['HeroService: fetched hero id=1']]),
117+
fail
118+
);
119+
});
120+
});
121+
122+
describe('when GET /api/heroes/{id} returns 404 Not Found', () => {
123+
beforeEach(() => {
124+
const errorResponse = new HttpErrorResponse({ status: 404, statusText: 'Not Found' });
125+
httpClientSpy.get.and.returnValue(asyncError(errorResponse));
126+
});
127+
128+
it ('should return undefined', () => {
129+
heroService.getHero(1).subscribe(
130+
response => expect(response).toEqual(undefined),
131+
fail
132+
);
133+
});
134+
135+
it ('should add a message to the message service', () => {
136+
const errorMessage = 'HeroService: getHero id=1 failed: Http failure response for (unknown url): 404 Not Found';
137+
heroService.getHero(1).subscribe(
138+
response => expect(messageServiceSpy.add.calls.allArgs()).toEqual([[errorMessage]]),
139+
fail
140+
);
141+
});
142+
});
143+
});
144+
145+
describe('#updateHero', () => {
146+
const hero: Hero = { id: 1, name: 'A' };
147+
148+
it('should call PUT /api/heroes/{id}', () => {
149+
httpClientSpy.put.and.returnValue(asyncData({}));
150+
heroService.updateHero(hero);
151+
expect(httpClientSpy.put.calls.allArgs()).toEqual([['api/heroes', hero, jasmine.any(Object)]]);
152+
});
153+
});
154+
155+
// describe('#updateHero', () => {
156+
// it('should return expected hero and log a message (HttpClient called once)', () => {
157+
// const updatedHero: Hero = { id: 1, name: 'A' };
158+
// httpClientSpy.put.and.returnValue(asyncData(updatedHero));
159+
//
160+
// heroService.updateHero({ id: 1, name: 'A' }).subscribe(
161+
// hero => {
162+
// expect(hero).toEqual(updatedHero);
163+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
164+
// expect(messageServiceSpy.add).toHaveBeenCalledWith('HeroService: updated hero id=1');
165+
// },
166+
// fail
167+
// );
168+
// expect(httpClientSpy.put.calls.count()).toBe(1);
169+
// });
170+
//
171+
// it('should log an error when the server returns a 404, and return no result', () => {
172+
// const errorResponse = new HttpErrorResponse({
173+
// error: 'test 404 error',
174+
// status: 404,
175+
// statusText: 'Not Found'
176+
// });
177+
// httpClientSpy.put.and.returnValue(asyncError(errorResponse));
178+
//
179+
// heroService.updateHero({ id: 1, name: 'A' }).subscribe(
180+
// hero => {
181+
// expect(hero).toBe(undefined);
182+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
183+
// expect(messageServiceSpy.add).toHaveBeenCalledWith(
184+
// 'HeroService: updateHero failed: Http failure response for (unknown url): 404 Not Found'
185+
// );
186+
// },
187+
// () => fail
188+
// );
189+
// });
190+
// });
191+
//
192+
// describe('#addHero', () => {
193+
// it('should return expected hero and log a message (HttpClient called once)', () => {
194+
// const addedHero: Hero = { id: 1, name: 'A' };
195+
// httpClientSpy.post.and.returnValue(asyncData(addedHero));
196+
//
197+
// heroService.addHero({ id: null, name: 'A' }).subscribe(
198+
// hero => {
199+
// expect(hero).toEqual(addedHero);
200+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
201+
// expect(messageServiceSpy.add).toHaveBeenCalledWith('HeroService: added hero w/ id=1');
202+
// },
203+
// fail
204+
// );
205+
// expect(httpClientSpy.post.calls.count()).toBe(1);
206+
// });
207+
//
208+
// it('should log an error when the server returns a 404, and return no result', () => {
209+
// const errorResponse = new HttpErrorResponse({
210+
// error: 'test 404 error',
211+
// status: 404,
212+
// statusText: 'Not Found'
213+
// });
214+
// httpClientSpy.post.and.returnValue(asyncError(errorResponse));
215+
//
216+
// heroService.addHero({ id: null, name: 'A' }).subscribe(
217+
// hero => {
218+
// expect(hero).toBe(undefined);
219+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
220+
// expect(messageServiceSpy.add).toHaveBeenCalledWith(
221+
// 'HeroService: addHero failed: Http failure response for (unknown url): 404 Not Found'
222+
// );
223+
// },
224+
// () => fail
225+
// );
226+
// });
227+
// });
228+
//
229+
// describe('#deleteHero', () => {
230+
// it('should return undefined and log a message (HttpClient called once)', () => {
231+
// const deletedHero: Hero = { id: 1, name: 'A' };
232+
// httpClientSpy.delete.and.returnValue(asyncData(undefined));
233+
//
234+
// heroService.deleteHero(deletedHero).subscribe(
235+
// hero => {
236+
// expect(hero).toEqual(undefined);
237+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
238+
// expect(messageServiceSpy.add).toHaveBeenCalledWith('HeroService: deleted hero id=1');
239+
// },
240+
// fail
241+
// );
242+
// expect(httpClientSpy.delete.calls.count()).toBe(1);
243+
// });
244+
//
245+
// it('should log an error when the server returns a 404, and return no result', () => {
246+
// const errorResponse = new HttpErrorResponse({
247+
// error: 'test 404 error',
248+
// status: 404,
249+
// statusText: 'Not Found'
250+
// });
251+
// httpClientSpy.delete.and.returnValue(asyncError(errorResponse));
252+
//
253+
// heroService.deleteHero({ id: null, name: 'A' }).subscribe(
254+
// hero => {
255+
// expect(hero).toBe(undefined);
256+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
257+
// expect(messageServiceSpy.add).toHaveBeenCalledWith(
258+
// 'HeroService: deleteHero failed: Http failure response for (unknown url): 404 Not Found'
259+
// );
260+
// },
261+
// () => fail
262+
// );
263+
// });
264+
// });
265+
//
266+
// describe('#searchHeroes', () => {
267+
// it('should return expected heroes and log a message (HttpClient called once)', () => {
268+
// const expectedHeroes: Hero[] = [
269+
// { id: 1, name: 'Aa' },
270+
// { id: 2, name: 'Ab' }
271+
// ];
272+
// httpClientSpy.get.and.returnValue(asyncData(expectedHeroes));
273+
//
274+
// heroService.searchHeroes('A').subscribe(
275+
// heroes => {
276+
// expect(heroes).toEqual(expectedHeroes);
277+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
278+
// expect(messageServiceSpy.add).toHaveBeenCalledWith('HeroService: found heroes matching "A"');
279+
// },
280+
// fail
281+
// );
282+
// expect(httpClientSpy.get.calls.count()).toBe(1);
283+
// });
284+
//
285+
// it('should log an error when the server returns a 404, and return an empty result', () => {
286+
// const errorResponse = new HttpErrorResponse({
287+
// error: 'test 404 error',
288+
// status: 404,
289+
// statusText: 'Not Found'
290+
// });
291+
// httpClientSpy.get.and.returnValue(asyncError(errorResponse));
292+
//
293+
// heroService.searchHeroes('A').subscribe(
294+
// heroes => {
295+
// expect(heroes).toEqual([]);
296+
// expect(messageServiceSpy.add.calls.count()).toBe(1);
297+
// expect(messageServiceSpy.add).toHaveBeenCalledWith(
298+
// 'HeroService: searchHeroes failed: Http failure response for (unknown url): 404 Not Found'
299+
// );
300+
// },
301+
// fail
302+
// );
303+
// });
304+
// });
23305
});

src/app/hero.service.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ export class HeroService {
6262
deleteHero (hero: Hero | number): Observable<Hero> {
6363
const id = typeof hero === 'number' ? hero : hero.id;
6464
const url = `${this.heroesUrl}/${id}`;
65-
6665
return this.http.delete<Hero>(url, httpOptions).pipe(
6766
tap(_ => this.log(`deleted hero id=${id}`)),
6867
catchError(this.handleError<Hero>('deleteHero'))
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Mock async observables that return asynchronously.
3+
* The observable either emits once and completes or errors.
4+
*
5+
* Must call `tick()` when test with `fakeAsync()`.
6+
*
7+
* THE FOLLOWING DON'T WORK
8+
* Using `of().delay()` triggers TestBed errors;
9+
* see https://github.com/angular/angular/issues/10127 .
10+
*
11+
* Using `asap` scheduler - as in `of(value, asap)` - doesn't work either.
12+
*/
13+
import { defer } from 'rxjs';
14+
15+
/**
16+
* Create async observable that emits-once and completes after a JS engine turn
17+
*/
18+
export function asyncData<T>(data: T) {
19+
return defer(() => Promise.resolve(data));
20+
}
21+
22+
/**
23+
* Create async observable error that errors after a JS engine turn
24+
*/
25+
export function asyncError<T>(errorObject: any) {
26+
return defer(() => Promise.reject(errorObject));
27+
}

0 commit comments

Comments
 (0)