wake-up-neo.com

How to mock Angular 4.3 httpClient eine Fehlerantwort beim Testen

Ich habe einen interceptor auth-interceptor.service.ts

import {Injectable, Injector} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';
import {UserService} from './user.service';
import {ToasterService} from '../toaster/toaster.service';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private injector: Injector) {}

    private handleError(err: HttpErrorResponse): Observable<any> {
        let errorMsg;
        if (err.error instanceof Error) {
            // A client-side or network error occurred. Handle it accordingly.
            errorMsg = `An error occurred: ${err.error.message}`;
        } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            errorMsg = `Backend returned code ${err.status}, body was: ${err.error}`;
        }
        if (err.status === 401 || err.status === 403) {
            this.injector.get(UserService).purgeAuth();
            this.injector.get(ToasterService).showError(`Unauthorized`, errorMsg);
            this.injector.get(Router).navigateByUrl(`/login`);
        }
        console.error(errorMsg);
        return Observable.throw(errorMsg);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // Pass on the cloned request instead of the original request.
        return next.handle(authReq).catch(err => this.handleError(err));
    }
}

Jetzt versuche ich, den http.get Zu verspotten, um den Fehler auszulösen, sodass die Methode handleError die Fehlermeldung tröstet.

Unten ist meine Herangehensweise an den Testfall auth-interceptor.service.specs.ts

import {async, inject, TestBed} from '@angular/core/testing';

import {AuthInterceptor} from './auth-interceptor.service';
import {ApiService} from './api.service';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {environment} from '../../../environments/environment';

describe(`AuthInterceptor`, () => {
    const somePath = `/somePath`;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [AuthInterceptor, ApiService]
        });
    });

    it(`should be created`, inject([AuthInterceptor], (service: AuthInterceptor) => {
        expect(service).toBeTruthy();
    }));


    it(`should log an error to the console on error on get()`, async(inject([ApiService, HttpTestingController],
        (apiService: ApiService, httpMock: HttpTestingController) => {
            spyOn(console, 'error');
            apiService.get(somePath).subscribe((res) => {
                console.log(`in success:`, res);
            }, (error) => {
                console.log(`in error:`, error);
            });

            const req = httpMock.expectOne(`${environment.apiUri}${somePath}`);
            req.flush({
                type: 'ERROR',
                status: 404,
                body: JSON.stringify({color: `blue`})
            });
            expect(console.error).toHaveBeenCalled();
        }))
    );
});

Wenn ich die Antwort lösche, bin ich mir nicht sicher, wie ich eine Fehlerantwort lösche, so dass die Methode handleError in meinem Interceptor aufgerufen wird und schließlich console.error Aufruft. Die Dokumentation hat kein Beispiel für meine Situation. Jede Hilfe oder Anregung wird geschätzt.

18
Sai Ram Gupta

Die Methode expectOne in der Klasse HttpTestingController gibt ein Objekt TestRequest zurück. Diese TestRequest-Klasse verfügt über eine flush -Methode, die zum Übermitteln verwendet werden kann

sowohl erfolgreiche als auch erfolglose Antworten.

Wir können die Anfrage lösen, indem wir einen Text zusammen mit einigen zusätzlichen Antwort-Headern (falls vorhanden) zurücksenden. Relevante Informationen finden Sie hier .

Kommen wir nun zu dem Punkt zurück, wie Sie dies tun können. Sie können das folgende Code-Snippet gemäß Ihrem Anwendungsfall anpassen.

http = TestBed.get(HttpTestingController);
let response: any;
let errResponse: any;
const mockErrorResponse = { status: 400, statusText: 'Bad Request' };
const data = 'Invalid request parameters';
apiService.get(somePath).subscribe(res => response = res, err => errResponse = err);
http.expectOne('url/being/monitored').flush(data, mockErrorResponse);
expect(errResponse).toBe(data);

[~ # ~] note [~ # ~] : Zum Zeitpunkt des Schreibens dieses Kommentars ist statusText in mockErrorResponse. Verwandte Informationen finden Sie hier .

PS : Die error -Methode der TestRequest -Klasse kann verwendet werden, um Netzwerkfehler in unserem Testfall so wie sie sind zu simulieren erwartet eine Instanz von Error. Das folgende Codefragment zeigt dies.

http.expectOne(someUrl).error(new ErrorEvent('network error'));
47
Rohit Sharma