import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { ApiConfigService } from '../core/config/api-config.service'; import { LocalStorageService } from '../core/storage/local-storage.service'; import { LocationService } from './location.service'; /** * FH-1.1. detectLocation() used to call http://ip-api.com directly. On an * HTTPS storefront the browser blocks mixed active content, so the request * never completed and region auto-detect silently did nothing in production * - and the attempt still exposed the visitor's IP to a third party. * * These tests pin both halves of the fix: geo resolution goes to our own * tenant API, and nothing in this service reaches a foreign origin. */ describe('LocationService', () => { const baseUrl = 'https://api.gorbushka.market'; let service: LocationService; let httpTesting: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ providers: [ LocationService, provideHttpClient(), provideHttpClientTesting(), { provide: ApiConfigService, useValue: { getBaseUrl: () => baseUrl } }, { provide: LocalStorageService, useValue: { getJSON: () => null, setJSON: () => {}, removeItem: () => {} }, }, ], }); service = TestBed.inject(LocationService); httpTesting = TestBed.inject(HttpTestingController); // The constructor loads regions; flush it so each test starts clean. httpTesting.expectOne(`${baseUrl}/regions`).flush([]); }); afterEach(() => httpTesting.verify()); it('resolves geo through the tenant API, not a third-party host', () => { service.detectLocation(); const request = httpTesting.expectOne(`${baseUrl}/geo/resolve`); expect(request.request.method).toBe('GET'); request.flush({ city: 'Москва', country: 'Россия', countryCode: 'RU' }); }); it('issues no request to a foreign or plaintext origin', () => { service.detectLocation(); for (const request of httpTesting.match(() => true)) { expect(request.request.url.startsWith(baseUrl)) .withContext(`unexpected off-origin request: ${request.request.url}`) .toBe(true); expect(request.request.url.startsWith('http://')) .withContext(`plaintext request: ${request.request.url}`) .toBe(false); request.flush({}); } }); it('degrades to the manual picker when geo resolution fails', () => { service.detectLocation(); httpTesting .expectOne(`${baseUrl}/geo/resolve`) .flush(null, { status: 503, statusText: 'Service Unavailable' }); expect(service.region()).toBeNull(); expect(service.detecting()).toBe(false); expect(service.autoDetected()).toBe(true); }); it('does not re-request geo once detection has been attempted', () => { service.detectLocation(); httpTesting.expectOne(`${baseUrl}/geo/resolve`).flush({ city: 'Ереван', country: 'Армения', countryCode: 'AM', }); service.detectLocation(); httpTesting.expectNone(`${baseUrl}/geo/resolve`); }); });