Я пытаюсь научиться юнит-тесту в угловых с жасмином и кармой. Я проверил свои методы, но не могу охватить catchError внутри метода pipe.
Это моя спецификация для тестирования сервиса. Он охватывает весь файл, кроме подписки и всех методов "catchError". Я перепробовал много вещей, и я не могу получить освещение для этого. Мое покрытие для этого файла на 71%, и мне нужно 90%:
class RouterStub {
navigateByUrl(url: string) {
return url;
}
}
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, 'assets/i18n/', '.json');
}
describe('AvatarService', () => {
let httpClientSpy: { get: jasmine.Spy };
const snackMock = {
openFromComponent() {
},
};
let spyDialogRef: any;
spyDialogRef = jasmine.createSpy();
spyDialogRef.componentInstance = {title: '', message: '', buttonClicked:
new EventEmitter() };
let httpMock: HttpTestingController;
spyDialogRef.afterClosed = () => of(true);
const spyMatDialog = jasmine.createSpyObj('MatDialog', ['open']);
spyMatDialog.open.and.returnValue(spyDialogRef);
const testQuote = 'Test Quote';
const serviceSpy = jasmine.createSpyObj('AvatarService',
['postAvatarData']);
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AvatarService,
SpinnerService,
AuthorizationService,
{provide: MatSnackBar, useValue: snackMock},
{provide: MatSnackBarRef, useValue: {instance: () => {}}},
{provide: MAT_SNACK_BAR_DATA, useValue: []},
{provide: MatDialogTitle, useValue: {}},
{provide: MatDialog, useValue: spyMatDialog},
{provide: MatDialogRef, useValue: spyMatDialog},
{provide: MAT_DIALOG_DATA, useValue: []},
{provide: Router, useClass: RouterStub},
ErrorService,
],
imports: [
OAuthModule.forRoot(),
HttpClientTestingModule,
LoggerTestingModule,
MatSnackBarModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
}),
],
});
httpClientSpy = jasmine.createSpyObj('HttpClient', ['post']);
httpMock = TestBed.get(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
it('should be created', inject([AvatarService], (service: AvatarService)
=> {
expect(service).toBeTruthy();
}));
it('', inject([AvatarService], (service: AvatarService) => {
service.count = 0;
service.isFirstTimeRequested();
service.isFirstTimeRequested();
service.snackBarErrorHandling('', '13123123123');
}));
it('postAvatars', inject([AvatarService], (service: AvatarService) => {
const mockAvatarData = {
nombre: 'pepe',
};
service.postAvatarData(mockAvatarData, 2, 3, 4
).subscribe((avatarData) => {
expect(avatarData.nombre).toEqual('pepe');
});
const req = httpMock.expectOne('https://rmp-
localhost:4200/rmp/v1/avatars');
expect(req.request.method).toEqual('POST');
req.flush(mockAvatarData);
httpMock.verify();
}));
it('repositionErrorHandling', inject([AvatarService], (service:
AvatarService) => {
const error = {status: 422};
const positionateForm = new FormGroup({
cTpElemento: new FormControl(''),
cElemento: new FormControl({value: {description: '213123123'},
disabled: true}),
cJsonDescElemento: new FormControl(''),
});
service.repositionErrorHandling(error, positionateForm, '', '', '');
}));
it('getAvatar', inject([AvatarService], (service: AvatarService) => {
const mockAvatarData = {
nombre: 'pepe',
};
service.getAvatars(1, 2, 3, 4).subscribe((avatarData) => {
expect(avatarData[0].nombre).toEqual('pepe');
});
const req = httpMock.expectOne('https://rmp-
localhost:4200/rmp/v1/avatars/assets?
refLatMin=1&refLatMax=2&refLonMin=3&refLonMax=4');
expect(req.request.method).toEqual('GET');
req.flush(mockAvatarData);
httpMock.verify();
}));
it('getSensorValue', inject([AvatarService], (service: AvatarService) => {
const mockAvatarData = {
nombre: 'pepe',
};
service.getSensorValue(1).subscribe((sensorData) => {
expect(sensorData[0].nombre).toEqual('pepe');
});
const req = httpMock.expectOne('https://rmp-
localhost:4200/rmp/v1/avatars/assets/1');
expect(req.request.method).toEqual('GET');
req.flush(mockAvatarData);
httpMock.verify();
}));
it('getAvatar second branch', inject([AvatarService], (service:
AvatarService) => {
const mockAvatarData = {
nombre: 'pepe',
};
service.getAvatars(1, 2, 3, 4, [1, 2, 3]).subscribe((avatarData) => {
expect(avatarData[0].nombre).toEqual('pepe');
});
const req = httpMock.expectOne('https://rmp-
localhost:4200/rmp/v1/avatars/assets?
refLatMin=1&refLatMax=2&refLonMin=3&refLonMax=4&lstAssetTypesId=1,2,3');
expect(req.request.method).toEqual('GET');
req.flush(mockAvatarData);
httpMock.verify();
}));
});
Это услуга, которую я хочу проверить:
count = 0;
constructor(private httpClient: HttpClient,
private snackBar: MatSnackBar,
private dialog: MatDialog,
private logger: NGXLogger,
private spinnerService: SpinnerService,
private translate: TranslateService,
private auth: AuthorizationService,
) {
}
isFirstTimeRequested() {
if (this.count === 0) {
this.spinnerService.changeSpinnerState(true);
} else {
this.spinnerService.changeSpinnerState(false);
}
this.count += 1;
}
snackBarErrorHandling(error, errorMessage) {
this.logger.error(error);
const snackBarRef =
this.snackBar.openFromComponent(SnackBarComponent, {
duration: 5000,
horizontalPosition: 'end',
verticalPosition: 'top',
panelClass: ['snack-color'],
data: {message: errorMessage },
});
snackBarRef.instance.dismiss$.pipe(take(1)).subscribe(()
=> {
snackBarRef.dismiss();
});
}
getAvatars(refLatMin, refLatMax, refLonMin, refLonMax,
lstAssetTypesId?): Observable<any> {
this.isFirstTimeRequested();
let errorMessage;
this.translate.get('avatar-service.get-
avatars').subscribe((value) => {
errorMessage = value;
});
let quoteParams = new HttpParams()
.set('refLatMin', refLatMin)
.set('refLatMax', refLatMax)
.set('refLonMin', refLonMin)
.set('refLonMax', refLonMax);
if (lstAssetTypesId) {
quoteParams = quoteParams.set('lstAssetTypesId',
lstAssetTypesId);
}
return this.httpClient
.get<Marker[]>(environment.baseUrlAvatars + '/assets',
{params: quoteParams})
.pipe(
tap(() => {
this.isFirstTimeRequested();
}),
retryWithBackoff(AppConfig.DEFAULT_DELAY),
catchError((error) => {
this.snackBarErrorHandling(error,
errorMessage);
return AppConfig.EMPTY_ARRAY;
}),
shareReplay(),
finalize(() => {
this.spinnerService.changeSpinnerState(false);
}),
);
}
getSensorValue(avatarId): Observable<Marker> {
let errorMessage;
this.translate.get('avatar-service.get-sensor-
value').subscribe((value) => {
errorMessage = value;
});
return this.httpClient.get<Marker>
(environment.baseUrlAvatars + '/assets/' + avatarId)
.pipe(
retryWithBackoff(AppConfig.DEFAULT_DELAY),
catchError((error) => {
this.snackBarErrorHandling(error,
errorMessage);
return AppConfig.EMPTY_ARRAY;
}),
shareReplay(),
);
}
openDialog(form) {
const config = {
data: {
assetDescription:
form.get('cElemento').value.description,
},
};
return this.dialog.open(DialogContentComponent, config);
}
postAvatarData(mark, sidenav, refreshData, form):
Observable<any> {
// tslint:disable-next-line: max-line-length
const options = {headers: new HttpHeaders().set('Content-
Type', 'application/json').set('Authorization', 'Bearer ' +
this.auth.getAccessToken())};
return this.httpClient.post<any>
(environment.baseUrlAvatars, JSON.stringify(mark), options).pipe(
catchError((error) => {
this.logger.error(error);
this.repositionErrorHandling(error, form, sidenav,
refreshData, mark);
return AppConfig.EMPTY_ARRAY;
}),
retryWithBackoff(AppConfig.DEFAULT_DELAY),
shareReplay(),
);
}
repositionErrorHandling(error, form, sidenav, refreshData,
mark) {
let errorMessage;
this.translate.get('avatar-service.post-avatar-
data').subscribe((value) => {
errorMessage = value;
});
if (error.status === 422) {
AppConfig.DEFAULT_DELAY = 0;
const dialogRef = this.openDialog(form);
dialogRef.componentInstance.buttonClicked.subscribe(async (result)
=> {
if (result) {
const headerPut = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Headers': 'Content-
Type',
};
const requestOptions = {
headers: new HttpHeaders(headerPut),
};
this.httpClient.put(environment.baseUrlAvatars, JSON.stringify(mark),
requestOptions).pipe(
catchError((errorPut) => {
this.snackBarErrorHandling(errorPut,
errorMessage);
return AppConfig.EMPTY_ARRAY;
}),
retryWithBackoff(AppConfig.DEFAULT_DELAY),
shareReplay()).subscribe();
await sidenav.toggle();
refreshData.emit();
}
});
} else {
this.snackBarErrorHandling(error, errorMessage);
}
}
// FJOR: not used
// retrieveAssetList(id): Observable<Asset2[]> {
// const quoteParams = new HttpParams().set('assetTypeId',
id);
// return this.httpClient.get<Asset2[]>
(environment.baseUrlAvatars + '/assets-types', {params: quoteParams});
// }
// FJOR: END not used
retrieveAssetTypeList(own?): Observable<Type[]> {
let errorMessage;
this.translate.get('avatar-service.retrieve-asset-
type').subscribe((value) => {
errorMessage = value;
});
if (own) {
const param = new HttpParams().set('own', own);
return this.httpClient.get<Type[]>
(environment.baseUrlAvatars + '/assets-types', {params: param})
.pipe(
retryWithBackoff(AppConfig.DEFAULT_DELAY),
catchError((error) => {
this.snackBarErrorHandling(error,
errorMessage);
return AppConfig.EMPTY_ARRAY;
}),
shareReplay(),
);
} else {
return this.httpClient.get<Type[]>
(environment.baseUrlAvatars + '/assets-types')
.pipe(
retryWithBackoff(AppConfig.DEFAULT_DELAY),
catchError((error) => {
this.snackBarErrorHandling(error,
errorMessage);
return AppConfig.EMPTY_ARRAY;
}),
shareReplay(),
);
}
}
}
Там у вас есть несколько примеров моегофайл покрытия кода для этой услуги
Пример 1
Пример 2