Testing Services and HTTP
Service Tests
1import { TestBed } from '@angular/core/testing';
2import { SamuraiService } from './samurai.service';
3
4describe('SamuraiService', () => {
5 let service: SamuraiService;
6
7 beforeEach(() => {
8 TestBed.configureTestingModule({
9 providers: [SamuraiService]
10 });
11 service = TestBed.inject(SamuraiService);
12 });
13
14 it('should be created', () => {
15 expect(service).toBeTruthy();
16 });
17
18 it('should calculate power level correctly', () => {
19 const result = service.calculatePower(10, 5);
20 expect(result).toBe(50);
21 });
22});
Testing HTTP with HttpTestingController
1import { TestBed } from '@angular/core/testing';
2import {
3 HttpTestingController,
4 provideHttpClientTesting
5} from '@angular/common/http/testing';
6import { provideHttpClient } from '@angular/common/http';
7import { SamuraiApiService } from './samurai-api.service';
8
9describe('SamuraiApiService', () => {
10 let service: SamuraiApiService;
11 let httpMock: HttpTestingController;
12
13 beforeEach(() => {
14 TestBed.configureTestingModule({
15 providers: [
16 SamuraiApiService,
17 provideHttpClient(),
18 provideHttpClientTesting()
19 ]
20 });
21
22 service = TestBed.inject(SamuraiApiService);
23 httpMock = TestBed.inject(HttpTestingController);
24 });
25
26 afterEach(() => {
27 // Verify no unhandled requests remain
28 httpMock.verify();
29 });
30
31 it('should fetch samurai list', () => {
32 const mockSamurai = [
33 { id: 1, name: 'Musashi', clan: 'Ronin' },
34 { id: 2, name: 'Jubei', clan: 'Yagyu' }
35 ];
36
37 service.getAll().subscribe(samurai => {
38 expect(samurai.length).toBe(2);
39 expect(samurai[0].name).toBe('Musashi');
40 });
41
42 // Intercept the request
43 const req = httpMock.expectOne('/api/samurai');
44 expect(req.request.method).toBe('GET');
45
46 // Simulate the response
47 req.flush(mockSamurai);
48 });
49
50 it('should send POST request to create samurai', () => {
51 const newSamurai = { name: 'Hanzo', clan: 'Iga' };
52 const savedSamurai = { id: 3, ...newSamurai };
53
54 service.create(newSamurai).subscribe(result => {
55 expect(result.id).toBe(3);
56 expect(result.name).toBe('Hanzo');
57 });
58
59 const req = httpMock.expectOne('/api/samurai');
60 expect(req.request.method).toBe('POST');
61 expect(req.request.body).toEqual(newSamurai);
62
63 req.flush(savedSamurai);
64 });
65
66 it('should handle HTTP errors', () => {
67 service.getById(999).subscribe({
68 next: () => fail('Should have failed'),
69 error: (error) => {
70 expect(error.status).toBe(404);
71 }
72 });
73
74 const req = httpMock.expectOne('/api/samurai/999');
75 req.flush('Not found', { status: 404, statusText: 'Not Found' });
76 });
77
78 it('should pass query parameters', () => {
79 service.search('Musashi', 'Ronin').subscribe();
80
81 const req = httpMock.expectOne(
82 req => req.url === '/api/samurai/search' &&
83 req.params.get('q') === 'Musashi' &&
84 req.params.get('clan') === 'Ronin'
85 );
86 expect(req.request.method).toBe('GET');
87
88 req.flush([]);
89 });
90});
Testing Interceptors
1import { TestBed } from '@angular/core/testing';
2import { HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
3import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
4import { authInterceptor } from './auth.interceptor';
5import { AuthService } from './auth.service';
6
7describe('AuthInterceptor', () => {
8 let httpClient: HttpClient;
9 let httpMock: HttpTestingController;
10 let authService: jasmine.SpyObj<AuthService>;
11
12 beforeEach(() => {
13 const authSpy = jasmine.createSpyObj('AuthService', ['getToken']);
14
15 TestBed.configureTestingModule({
16 providers: [
17 provideHttpClient(withInterceptors([authInterceptor])),
18 provideHttpClientTesting(),
19 { provide: AuthService, useValue: authSpy }
20 ]
21 });
22
23 httpClient = TestBed.inject(HttpClient);
24 httpMock = TestBed.inject(HttpTestingController);
25 authService = TestBed.inject(AuthService) as jasmine.SpyObj<AuthService>;
26 });
27
28 it('should add Authorization header when token exists', () => {
29 authService.getToken.and.returnValue('test-token');
30
31 httpClient.get('/api/samurai').subscribe();
32
33 const req = httpMock.expectOne('/api/samurai');
34 expect(req.request.headers.get('Authorization')).toBe('Bearer test-token');
35 req.flush([]);
36 });
37
38 it('should not add header when no token', () => {
39 authService.getToken.and.returnValue(null);
40
41 httpClient.get('/api/samurai').subscribe();
42
43 const req = httpMock.expectOne('/api/samurai');
44 expect(req.request.headers.has('Authorization')).toBeFalse();
45 req.flush([]);
46 });
47});