Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
9.7 kB
1
Indexable
Never
import { HttpClient } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { of } from 'rxjs';
import { mockLocationCheckResponse } from 'src/app/mocks/location.mock';
import { AALocation } from '../models';
import { EnvService } from './env.service';
import { AALocationService } from './location.service';

describe('AALocationService', () => {
  let aaLocationService: AALocationService;
  let httpClientSpy: jasmine.SpyObj<HttpClient>;
  let routerSpy: jasmine.SpyObj<Router>;
  let envServiceSpy: jasmine.SpyObj<EnvService>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
    });
    httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
    envServiceSpy = jasmine.createSpyObj('EnvService', ['']);
    envServiceSpy.customerPoliciesURL = '/test';
    routerSpy = jasmine.createSpyObj('Router', ['']);
    routerSpy.navigate = jasmine.createSpy();
    httpClientSpy.get = jasmine.createSpy().and.returnValue(of(mockLocationCheckResponse));
    aaLocationService = new AALocationService(httpClientSpy, routerSpy, envServiceSpy);
  });

  it('should be created', () => {
    expect(aaLocationService).toBeTruthy();
  });

  it('should call getGeolocation', () => {
    spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake((...args: any[]) => {
      const position = { coords: { latitude: 0, longitude: 0 } };
      args[0](position);
    });

    aaLocationService.getGeolocation().subscribe((data) => {
      expect(data.location.latitude).toBe(0);
      expect(data.location.longitude).toBe(0);
    });
  });

  it('should call getGeolocation with error', () => {
    spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake((...args: any[]) => {
      const error = {
        code: 'noPermission',
      };
      args[1](error.code);
    });

    aaLocationService.getGeolocation().subscribe((errorObj) => {
      expect(errorObj.error).toBe('noPermission');
    });
  });

  it('should call checkLocation', () => {
    aaLocationService.checkLocation({ latitude: 1, longitude: 1 }).subscribe((data) => {
      expect(data).toEqual(mockLocationCheckResponse);
    });
  });

  it('should call checkLocationFromLocation', () => {
    spyOn(aaLocationService, 'checkLocation').and.returnValue(of(mockLocationCheckResponse));
    aaLocationService.checkLocationFromLocation(mockLocationCheckResponse as AALocation);
    expect(aaLocationService.checkLocation).toHaveBeenCalled();
  });

  it('should call checkLocationFromLocation', () => {
    spyOn(aaLocationService, 'checkLocation').and.returnValue(of(mockLocationCheckResponse));
    aaLocationService.checkLocationFromLocation(mockLocationCheckResponse as AALocation).subscribe((_x) => {
      expect(aaLocationService.checkLocation).toHaveBeenCalled();
    });
  });

  it('should call checkLocationFromLocation', () => {
    spyOn(aaLocationService, 'checkLocation').and.returnValue(of(null));
    aaLocationService.checkLocationFromLocation(mockLocationCheckResponse as AALocation).subscribe((_x) => {
      expect(aaLocationService.checkLocation).toHaveBeenCalled();
    });
  });

  it('should call getLocationFromGeolocationOnce', () => {
    spyOn(aaLocationService, 'getGeolocation').and.returnValue(of(mockLocationCheckResponse));
    aaLocationService.getLocationFromGeolocation();
    expect(aaLocationService.getGeolocation).toHaveBeenCalled();
  });

  it('should call processLocationResult', () => {
    let loc = {
      location: {
        isAllowed: false,
        minAccuracy: 1,
        isAccurate: function () {
          return true;
        },
      },
    };
    spyOn(aaLocationService, 'checkLocationFromLocation');
    aaLocationService['processLocationResult'](loc);
    expect(aaLocationService.checkLocationFromLocation).toHaveBeenCalledWith(loc.location);
  });

  it('getLocationFromAddress$', async () => {
    spyOn(aaLocationService, 'getLocationFromAddress').and.returnValue(of({}).toPromise());
    aaLocationService.getLocationFromAddress$('456677').subscribe((_x) => {
      expect(aaLocationService.getLocationFromAddress).toHaveBeenCalled();
    });
  });
});
.
.
.
.
.
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { from, Observable, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';

import { environment } from 'src/environments/environment';
import { SETTINGS } from '../app.settings';
import { AALocation, ILocationCheckResponse, ILocationResult, LocationErrorCode } from '../models';
import { ICustomerDetails } from '../models/policy.model';
import { RaboRoutes } from '../routing/rabo-routes.model';
import { EnvService } from './env.service';

@Injectable({ providedIn: 'root' })
export class AALocationService {
  constructor(private http: HttpClient, private router: Router, private envService: EnvService) {}

  getGeolocation(): Observable<ILocationResult> {
    return new Observable<ILocationResult>((observer) => {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(
          ({ coords }) => {
            observer.next({ location: new AALocation(coords) });
            observer.complete();
          },
          (error) => {
            if (error.code === error.PERMISSION_DENIED) {
              observer.next({ error: LocationErrorCode.noPermission });
              observer.complete();
            }
            if (error.code === error.POSITION_UNAVAILABLE) {
              observer.next({ error: LocationErrorCode.notAvailable });
              observer.complete();
            }
          },
          SETTINGS.positionOptions
        );
      } else {
        observer.next({ error: LocationErrorCode.unknown });
        observer.complete();
      }
    });
  }

  getLocationFromGeolocation(): Observable<ILocationResult> {
    return this.getGeolocation().pipe(
      switchMap((loc) => {
        return !loc.error ? this.processLocationResult(loc) : of(loc);
      })
    );
  }

  private processLocationResult(loc: ILocationResult): Observable<ILocationResult> {
    loc.location.isAllowed = true;
    loc.location.minAccuracy = SETTINGS.googleMaps.mapOptions.minAccuracy;
    return loc.location.isAccurate() ? this.checkLocationFromLocation(loc.location) : of({ location: loc.location });
  }

  checkLocationFromLocation(location: AALocation): Observable<ILocationResult> {
    return this.checkLocation(location).pipe(
      map((result) => {
        if (result && result.location) {
          location.latitude = result.location.coordinates.latitude;
          location.longitude = result.location.coordinates.longitude;
          location.dangerousLocation = result.dangerousLocation;
          location.motorway = result.motorway;
          location.area = result.location.area;
          location.text = result.location.text;
          location.formattedAddressFromGeoLocation = result.formatted_address;
          return { location };
        } else {
          this.router.navigate([RaboRoutes.Error, 'TryAgainErrorPage'], { queryParamsHandling: 'preserve' });

          return { error: LocationErrorCode.nullLocationResponse };
        }
      })
    );
  }

  checkLocation({ longitude, latitude }: AALocation): Observable<ILocationCheckResponse> {
    const params: HttpParams = new HttpParams().set('lat', latitude?.toString()).set('lng', longitude?.toString());
    return this.http
      .get<ILocationCheckResponse>(environment.locationCheckURL, { params })
      .pipe(catchError(() => of({} as ILocationCheckResponse)));
  }

  getLocationFromAddress$(postCode: string, firstLineOfAddress?: string): Observable<AALocation> {
    return from(this.getLocationFromAddress(postCode, firstLineOfAddress));
  }

  async getLocationFromAddress(postCode: string, firstLineOfAddress?: string): Promise<AALocation> {
    const geocoder = new google.maps.Geocoder();
    postCode = postCode.trim().replace(/\s+/g, ' ').toUpperCase();

    return new Promise((resolve, reject) => {
      const address = firstLineOfAddress ? `${firstLineOfAddress}, ${postCode}` : postCode;
      geocoder.geocode(
        {
          address,
          componentRestrictions: { country: 'UK' },
        },
        (results, status) => {
          if (status === 'OK') {
            const slicedPostCode = new RegExp(postCode.replace(/\s.*$/, '').slice(0, 4), 'i');
            if (slicedPostCode.test(results[0].formatted_address)) {
              resolve({
                latitude: results[0].geometry.location.lat(),
                longitude: results[0].geometry.location.lng(),
              });
            } else if (firstLineOfAddress) {
              resolve(this.getLocationFromAddress(postCode));
            } else {
              reject({ error: status });
            }
          } else if (status === 'ZERO_RESULTS' && firstLineOfAddress) {
            resolve(this.getLocationFromAddress(postCode));
          } else {
            reject({ error: status });
          }
        }
      );
    });
  }

  getPoliciesDetails(): Observable<ICustomerDetails> {
    return this.http.get<ICustomerDetails>(this.envService.customerPoliciesURL).pipe(
      map((value: any) => value.customerDetails as ICustomerDetails),
      catchError(() => of(null))
    );
  }
}