Angular2 problems with testing an interceptor that extends the HTTP module

I am currently creating an Angular2 application, which I am in the middle of writing tests, but I ran into a problem that I cannot solve when creating a test module.

I created my own class that extends the Angular2 HTTP module and works as an interceptor. This class is responsible for authentication logic and other similar things.

Here is the HttpInterceptor class. This is used instead of the main Angular2 HTTP class and is just an extension of it:

import { Injectable, Inject } from "@angular/core"; import { Http, ConnectionBackend, RequestOptions, Request, RequestOptionsArgs, Response } from "@angular/http"; import { Observable } from "rxjs"; import { AuthService } from "./auth.service"; import { GlobalEventsManager } from "./globalEventsManager.service"; import { messages } from "../helpers/messages"; @Injectable() export class HttpInterceptor extends Http { constructor( backend: ConnectionBackend, defaultOptions: RequestOptions, public _authService: AuthService, public _globalEventsManager: GlobalEventsManager ) { super(backend, defaultOptions); } request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { return super.request(url, options).catch(res => { if(res.statusCode === 401) { console.log('expired'); } }); } get(url: string, options?: RequestOptionsArgs): Observable<Response> { var obsStream = super.request(url, options); obsStream.subscribe((data) => { var JSONParsedRes = JSON.parse(data._body); if(JSONParsedRes.statusCode) { if(JSONParsedRes.statusCode == 401) { this._globalEventsManager.showNavBar.emit(false); this._authService.logout({message: messages.messages.auth.tokenExpired, title:messages.titles.auth.tokenExpired}); } } }); return obsStream; } handleError() { console.log('error'); } } 

Here is the service I'm trying to check:

 import { Injectable, EventEmitter } from "@angular/core"; import { RequestOptions } from "@angular/http"; import { Product } from "../classes/Product"; import { Observable } from "rxjs"; import { routes } from "../routes"; import { StringHelper } from "../helpers/StringHelper"; import { HttpHelper } from "../helpers/HttpHelper"; import { HttpInterceptor } from "./HttpInterceptor.service"; @Injectable() export class ProductService { public emitter: EventEmitter<any> = new EventEmitter(); private APIUrl:String; constructor( private _http: HttpInterceptor ) { } getProduct(id:number): Observable<Product> { let headers = HttpHelper.createAuthorizationHeader(true, false); let options = new RequestOptions({ headers: headers }); return this._http .get(routes.api.products + '/' + id, options) .map(res => res.json()); } /** * Get all products * return Observable */ getProducts(filters:Object): Observable<Product[]> { let headers = HttpHelper.createAuthorizationHeader(true, false); let options = new RequestOptions({ headers: headers }); return this._http .get(routes.api.products + StringHelper.convertVarsToString(filters), options) .map(res => res.json()); } editProduct(payload) { let headers = HttpHelper.createAuthorizationHeader(true, false); let options = new RequestOptions({ headers: headers }); payload['_method'] = 'PUT'; return this._http .post(routes.api.products + '/' + payload.product.id, payload, options) .map(res => res.json()); } /** * Add products to EventEmitter stream */ public emitProducts(products): void { this.emitter.emit(products); } } 

As you can see, I am dependent on the injection of the HttpInterceptor class instead of the underlying Http to use the user logic included in my Interceptor. This works just fine and the application works as expected. The problem I am facing is when I try to configure my testing module to use this HttpInterceptor class, an error occurs. Here is my testing module:

 import { ProductService } from "../../services/product.service"; import { TestBed } from "@angular/core/testing"; import { HttpModule, Http, BaseRequestOptions } from "@angular/http"; import { MockBackend } from "@angular/http/testing"; import {HttpInterceptor} from "../../services/HttpInterceptor.service"; import {AuthService} from "../../services/auth.service"; import {GlobalEventsManager} from "../../services/globalEventsManager.service"; describe('Service: productService', () => { let prodService: ProductService; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], providers: [ { provide: HttpInterceptor, useFactory: (mockBackend, options, _authService, _globalEventsManager) => { return new HttpInterceptor(mockBackend, options, _authService, _globalEventsManager); }, deps: [MockBackend, BaseRequestOptions, AuthService, GlobalEventsManager] }, MockBackend, BaseRequestOptions, ProductService ] }); }); }); 

I know that I need to provide the HttpInterceptor class in the configureTestingModule method for this test to work. Unfortunately, this causes an error. As you can see, I use useFactory to instantiate the HttpInterceptor itself and provide all the dependencies that are also needed (MockBackend, BaseRequestOptions, AuthService, GlobalEventsManager). I'm not sure why this is causing the error?

I played a little and when I change the dependency in the ProductService constructor:

 @Injectable() export class ProductService { public emitter: EventEmitter<any> = new EventEmitter(); private APIUrl:String; constructor( private _http: HttpInterceptor ) { } 

:

 @Injectable() export class ProductService { public emitter: EventEmitter<any> = new EventEmitter(); private APIUrl:String; constructor( private _http: Http ) { } 

And then provide the main Http module in the test module, as shown here, the testing module works without errors.

 { provide: Http, useFactory: (mockBackend, options) => { return new Http(mockBackend, options); }, deps: [MockBackend, BaseRequestOptions] }, 

This means that there is a problem introducing an instance of my HttpInterceptor class into the testing module, and I cannot understand why. Can anyone understand why this will happen?

+5
source share

Source: https://habr.com/ru/post/1261203/


All Articles