web-dev-qa-db-fra.com

Comment simuler Angular 4.3 httpClient une réponse d'erreur lors du test

J'ai un ci-dessous 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));
    }
}

Maintenant j'essaie de me moquer du http.get pour renvoyer l'erreur, de sorte que la méthode handleError console le message d'erreur.

Ci-dessous, mon approche du cas de test 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();
        }))
    );
});

Lors du vidage de la réponse, je ne sais pas comment vider une réponse d'erreur, de sorte que la méthode handleError soit appelée dans mon intercepteur et que finalement, elle appelle console.error. La documentation n'a pas d'exemple à ma situation. Toute aide ou suggestion est appréciée.

18
Sai Ram Gupta

La méthode expectOne de la classe HttpTestingController renvoie un objet TestRequest. Cette classe TestRequest a une méthode flush qui peut être utilisée pour livrer

les réponses réussies et non réussies.

Nous pouvons résoudre la demande en renvoyant un corps avec quelques en-têtes de réponse supplémentaires (le cas échéant). Des informations pertinentes peuvent être trouvées ici .

Revenons maintenant à la façon dont vous pouvez y arriver. Vous pouvez personnaliser l'extrait de code ci-dessous selon votre cas d'utilisation.

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 [~ # ~] : Au moment de la rédaction de ce commentaire, statusText est requis dans mockErrorResponse. Des informations connexes peuvent être trouvées ici .

PS : La méthode error de TestRequest class peut être utilisée pour simuler une erreur réseau dans notre cas de test, car elle attend une instance de Error. L'extrait de code suivant montre cela.

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