Тестирование сервиса, не способного получить покрытие оператора catchError rjxs - PullRequest
0 голосов
/ 21 октября 2019

Я пытаюсь научиться юнит-тесту в угловых с жасмином и кармой. Я проверил свои методы, но не могу охватить 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

...