Skip to content

Commit a49a93f

Browse files
committed
WEB-840: Implement Unit Test Suite for AuthenticationInterceptor
1 parent abf9bac commit a49a93f

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/**
2+
* Copyright since 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
import { TestBed } from '@angular/core/testing';
10+
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
11+
import { provideHttpClient, withInterceptorsFromDi, HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
12+
import { firstValueFrom } from 'rxjs';
13+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
14+
15+
import { AuthenticationInterceptor } from './authentication.interceptor';
16+
import { SettingsService } from 'app/settings/settings.service';
17+
import { environment } from 'environments/environment';
18+
19+
describe('AuthenticationInterceptor', () => {
20+
let interceptor: AuthenticationInterceptor;
21+
let httpMock: HttpTestingController;
22+
let http: HttpClient;
23+
24+
const mockSettingsService: { tenantIdentifier: string | null } = {
25+
tenantIdentifier: null
26+
};
27+
28+
beforeEach(() => {
29+
TestBed.configureTestingModule({
30+
providers: [
31+
AuthenticationInterceptor,
32+
provideHttpClient(withInterceptorsFromDi()),
33+
provideHttpClientTesting(),
34+
{ provide: SettingsService, useValue: mockSettingsService },
35+
{ provide: HTTP_INTERCEPTORS, useExisting: AuthenticationInterceptor, multi: true }]
36+
});
37+
interceptor = TestBed.inject(AuthenticationInterceptor);
38+
httpMock = TestBed.inject(HttpTestingController);
39+
http = TestBed.inject(HttpClient);
40+
});
41+
42+
afterEach(() => {
43+
httpMock.verify();
44+
interceptor.removeAuthorizationTenant();
45+
interceptor.removeTwoFactorAuthorization();
46+
mockSettingsService.tenantIdentifier = null;
47+
});
48+
49+
describe('intercept', () => {
50+
it('should set Fineract-Platform-TenantId on internal requests', async () => {
51+
const resultPromise = firstValueFrom(http.get('/clients'));
52+
53+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
54+
expect(req.request.headers.get('Fineract-Platform-TenantId')).toBe(environment.fineractPlatformTenantId);
55+
56+
req.flush([]);
57+
await resultPromise;
58+
});
59+
60+
it('should use custom tenant from SettingsService when set', async () => {
61+
mockSettingsService.tenantIdentifier = 'custom-tenant';
62+
const resultPromise = firstValueFrom(http.get('/clients'));
63+
64+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
65+
expect(req.request.headers.get('Fineract-Platform-TenantId')).toBe('custom-tenant');
66+
67+
req.flush([]);
68+
await resultPromise;
69+
});
70+
71+
it('should pass https external URLs through without Fineract headers', async () => {
72+
const resultPromise = firstValueFrom(http.get('https://api.external.com/data'));
73+
74+
const req = httpMock.expectOne((r) => r.url === 'https://api.external.com/data' && r.method === 'GET');
75+
expect(req.request.headers.has('Fineract-Platform-TenantId')).toBe(false);
76+
77+
req.flush({});
78+
await resultPromise;
79+
});
80+
81+
it('should pass http external URLs through without Fineract headers', async () => {
82+
const resultPromise = firstValueFrom(http.get('http://api.external.com/data'));
83+
84+
const req = httpMock.expectOne((r) => r.url === 'http://api.external.com/data' && r.method === 'GET');
85+
expect(req.request.headers.has('Fineract-Platform-TenantId')).toBe(false);
86+
87+
req.flush({});
88+
await resultPromise;
89+
});
90+
91+
it('should include Authorization header on requests when previously set', async () => {
92+
interceptor.setAuthorizationToken('dGVzdDp0ZXN0');
93+
const resultPromise = firstValueFrom(http.get('/clients'));
94+
95+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
96+
expect(req.request.headers.get('Authorization')).toBe('Basic dGVzdDp0ZXN0');
97+
98+
req.flush([]);
99+
await resultPromise;
100+
});
101+
});
102+
103+
describe('setAuthorizationToken', () => {
104+
it('should set Basic prefix when OAuth is disabled', async () => {
105+
const originalOAuth = environment.oauth.enabled;
106+
try {
107+
environment.oauth.enabled = false;
108+
interceptor.setAuthorizationToken('dGVzdDp0ZXN0');
109+
110+
const resultPromise = firstValueFrom(http.get('/clients'));
111+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
112+
expect(req.request.headers.get('Authorization')).toBe('Basic dGVzdDp0ZXN0');
113+
114+
req.flush([]);
115+
await resultPromise;
116+
} finally {
117+
environment.oauth.enabled = originalOAuth;
118+
}
119+
});
120+
121+
it('should set Bearer prefix when OAuth is enabled', async () => {
122+
const originalOAuth = environment.oauth.enabled;
123+
try {
124+
environment.oauth.enabled = true;
125+
interceptor.setAuthorizationToken('my-oauth-token');
126+
127+
const resultPromise = firstValueFrom(http.get('/clients'));
128+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
129+
expect(req.request.headers.get('Authorization')).toBe('Bearer my-oauth-token');
130+
131+
req.flush([]);
132+
await resultPromise;
133+
} finally {
134+
environment.oauth.enabled = originalOAuth;
135+
}
136+
});
137+
});
138+
139+
describe('Two-Factor Authentication', () => {
140+
it('should set Fineract-Platform-TFA-Token header', async () => {
141+
interceptor.setTwoFactorAccessToken('tfa-token-123');
142+
const resultPromise = firstValueFrom(http.get('/clients'));
143+
144+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
145+
expect(req.request.headers.get('Fineract-Platform-TFA-Token')).toBe('tfa-token-123');
146+
147+
req.flush([]);
148+
await resultPromise;
149+
});
150+
151+
it('should remove TFA header after removeTwoFactorAuthorization', async () => {
152+
interceptor.setTwoFactorAccessToken('tfa-token-123');
153+
interceptor.removeTwoFactorAuthorization();
154+
155+
const resultPromise = firstValueFrom(http.get('/clients'));
156+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
157+
expect(req.request.headers.has('Fineract-Platform-TFA-Token')).toBe(false);
158+
159+
req.flush([]);
160+
await resultPromise;
161+
});
162+
});
163+
164+
describe('removeAuthorization / removeAuthorizationTenant', () => {
165+
it('should remove only Authorization header and keep tenant', async () => {
166+
mockSettingsService.tenantIdentifier = environment.fineractPlatformTenantId;
167+
interceptor.setAuthorizationToken('dGVzdDp0ZXN0');
168+
interceptor.removeAuthorization();
169+
170+
const resultPromise = firstValueFrom(http.get('/clients'));
171+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
172+
expect(req.request.headers.has('Authorization')).toBe(false);
173+
expect(req.request.headers.has('Fineract-Platform-TenantId')).toBe(true);
174+
175+
req.flush([]);
176+
await resultPromise;
177+
});
178+
179+
it('should remove both Authorization and tenant headers', async () => {
180+
interceptor.setAuthorizationToken('dGVzdDp0ZXN0');
181+
interceptor.removeAuthorizationTenant();
182+
183+
const resultPromise = firstValueFrom(http.get('/clients'));
184+
const req = httpMock.expectOne((r) => r.url === '/clients' && r.method === 'GET');
185+
expect(req.request.headers.has('Authorization')).toBe(false);
186+
expect(req.request.headers.has('Fineract-Platform-TenantId')).toBe(false);
187+
188+
req.flush([]);
189+
await resultPromise;
190+
});
191+
});
192+
});

0 commit comments

Comments
 (0)