We use cookies to enhance your experience on the site
CodeWorlds

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});
Go to CodeWorlds