У меня есть эти два служебных файла, один из которых включен в другой.
app.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { throwError, Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Router } from '@angular/router';
import { environment } from '../../environments/environment';
import { AuthService } from '../_services/auth.service';
@Injectable({
providedIn: 'root'
})
export class AppService {
protected _apiURL = environment.apiURL;
// Define URLs here
_overviewURL: string;
_deleteUserUrl: string;
constructor(private http: HttpClient,
private _router: Router,
private _authService: AuthService) {
this.setApiUrl();
}
/* Begin: Misc services */
/**
* @description Sets the header for each request
* @param authorize Flag to whether include authorization token in headers or not
* @returns - Header consisting of Authorization token & Content-type
*/
setHeaders(authorize: boolean = false) {
const headers: any = {};
headers['Content-Type'] = 'application/json';
if (authorize && this._authService.isAuthenticated()) {
const authenticated = this._authService.getAuthenticatedUser();
headers.Authorization = `Bearer ${authenticated.idToken}`;
}
return {
headers: new HttpHeaders(headers)
};
}
/**
* @description Sets all the service URLs with the respective endpoints
*/
setApiUrl() {
this._overviewURL = this._apiURL + 'overview';
this._deleteUserUrl = this._apiURL + 'user/delete';
}
/**
* @description Gets the user overview page details based on BGtOccName & BGtID
* @param params - consists of BGtOccName & BGtId (BG Occupation Name & BG Occupation ID).
* Refer BG Docs: https://dev.burning-glass.com/docs/versions/3.3/getting-started
*/
getOverviewPageInfo(params: any) {
return this.http.post(this._overviewURL, params, this.setHeaders())
.pipe(
map(this.handleResponse),
catchError(this.handleError)
);
}
/**
* @description Delete an authenticated user
* @param user User object from localStorage
*/
deleteUser(user: any) {
return this.http.post(this._deleteUserUrl, user, this.setHeaders(true))
.pipe(
map(this.handleResponse),
catchError(this.handleError)
);
}
/**
* @description processes observable response
* @param res - takes in the response object
* @returns - data object
*/
private handleResponse = (res: any) => {
return res.data || {};
}
/**
* @description processes observable error
* @param error - takes in the error object
* @returns - error object
*/
private handleError = (error: Response | any) => {
console.error(error.error.message || error.message);
const errorMsg = error.error.message || error.message;
if (errorMsg === 'Invalid token') { this._router.navigate(['/login']); localStorage.removeItem('loggedUser'); }
return throwError(error.error.error);
}
}
auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from '../../environments/environment';
import * as auth0 from 'auth0-js';
import { ToastrService } from 'ngx-toastr';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private _idToken: string;
private _accessToken: string;
private _expiresAt: number;
private auth0User: any;
auth0 = new auth0.WebAuth({
clientID: environment.AUTH0_CLIENTID,
domain: environment.AUTH0_DOMAIN,
responseType: 'token id_token',
redirectUri: environment.AUTH0_REDIRECT_URI
});
constructor( public router: Router,
private _toastr: ToastrService) {
this.auth0User = JSON.parse(localStorage.getItem('auth0User'));
this._idToken = (this.auth0User && this.auth0User.idToken) ? this.auth0User.idToken : '';
this._accessToken = (this.auth0User && this.auth0User.accessToken) ? this.auth0User.accessToken : '';
this._expiresAt = (this.auth0User && this.auth0User.expiresAt) ? this.auth0User.expiresAt : 0;
}
get accessToken(): string {
return this._accessToken;
}
get idToken(): string {
return this._idToken;
}
public login(): void {
this.auth0.authorize();
}
public handleAuthentication(): void {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.localLogin(authResult);
this.router.navigate(['/home']);
this._toastr.success(`You have been logged in!`, `Success`);
} else if (err) {
this.router.navigate(['/home']);
this._toastr.error(`Invalid login`, `Failed`);
}
});
}
private localLogin(authResult): void {
// Set the time that the access token will expire at
const expiresAt = (authResult.expiresIn * 1000) + Date.now();
this._accessToken = authResult.accessToken;
this._idToken = authResult.idToken;
this._expiresAt = expiresAt;
let auth0User: any = localStorage.getItem('auth0User');
if (auth0User) {
auth0User = JSON.parse(auth0User);
auth0User.idToken = authResult.idToken;
auth0User.expiresAt = expiresAt;
auth0User.accessToken = authResult.accessToken;
localStorage.setItem('auth0User', JSON.stringify(auth0User));
} else {
localStorage.setItem('auth0User', JSON.stringify({
idToken: authResult.idToken,
expiresAt: expiresAt,
accessToken: authResult.accessToken,
idTokenPayload: authResult.idTokenPayload
}));
}
}
public renewTokens(): void {
this.auth0.checkSession({}, (err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.localLogin(authResult);
} else if (err) {
this._toastr.error(`Could not get a new token (${err.error}: ${err.error_description}).`, `Failed`);
this.logout();
}
});
}
public logout(): void {
// Remove tokens and expiry time
this._accessToken = '';
this._idToken = '';
this._expiresAt = 0;
localStorage.removeItem('auth0User');
this.auth0.logout({
returnTo: window.location.origin
});
this._toastr.success(`You have been logged out!`, `Success`);
}
public isAuthenticated(): boolean {
// Check whether the current time is past the
// access token's expiry time
return this._accessToken && Date.now() < this._expiresAt;
}
public getAuthenticatedUser() {
if (localStorage.getItem('auth0User')) {
return JSON.parse(localStorage.getItem('auth0User'));
} else {
return null;
}
}
}
Каждый раз, когда я запускаю свой тестовый файл app.service.spec.ts, он выдает ошибку, которая не приводит ни к какому коду.
app.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppService } from './app.service';
describe('AppService', () => {
let service: AppService;
let httpMock: HttpTestingController;
beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule
],
providers: [AppService]
}));
beforeEach(() => {
service = TestBed.get(AppService);
httpMock = TestBed.get(HttpTestingController);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
afterEach(() => {
httpMock.verify();
});
it('should retrieve overview details', () => {
const postParams = {
'designation': 'Fire Chief / Marshal',
'id': '378'
};
const overviewDetails = {
'data': {
'highSalary': 115511.77,
'estimatedSalary': 98935,
'nationalSalary': 98498.34,
'skills': [
{
'name': 'JavaScript Object Notation (JSON)',
'description': 'In computing, JavaScript Object Notation or JSON ( JAY-sn), is an open-standard ' +
'file format that uses human-readable text to transmit data objects consisting of' +
'attributevalue pairs and array data types (or any other serializable value).',
'count': 45084
},
{
'name': 'Software Architecture',
'description': 'Software architecture refers to the high level structures of a software system,' +
'the discipline of creating such structures, and the documentation of these structures.',
'count': 42676
}
],
'careers': [
{
'name': 'Chief Executive Officer',
'meanSalaryDiff': 11347.74
},
{
'name': 'Database Architect',
'meanSalaryDiff': 7699.84
}
]
}
};
service.getOverviewPageInfo(postParams).subscribe(overview => {
expect(overview).toEqual(overviewDetails.data);
});
const req = httpMock.expectOne(service._overviewURL);
expect(req.request.method).toBe('POST');
req.flush(overviewDetails);
});
});
Однако если удалить строки
if (authorize && this._authService.isAuthenticated()) {
const authenticated = this._authService.getAuthenticatedUser();
headers.Authorization = `Bearer ${authenticated.idToken}`;
}
из файла app.service.ts, то весь тест работает нормально (как вы можете видеть, он вызываетфункции authService).
Я пытался включить authService в поставщиков app.service.spec.ts, как показано ниже, но безуспешно.: (
beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule
],
providers: [AppService, AuthService]
}));
Мой вопрос: как включить / проверить один инъекционный (сервис) в другой инъецируемый файл?