测试拦截器的Angular2问题扩展了HTTP模块

Jim*_*Jim 5 testing dependency-injection jasmine angular

我目前正在构建一个Angular2应用程序,我正在编写测试,但是我遇到了一个在创建测试模块时似乎无法解决的问题.

我创建了一个自定义类,它扩展了Angular2 HTTP模块并用作拦截器.该类负责身份验证逻辑和其他类似的事情.

这是HttpInterceptor类.这用来代替Angular2 HTTP核心类,它只是它的扩展:

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');
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我试图测试的服务:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我是依赖注入HttpInterceptor类而不是基本Http类,以便使用我的拦截器中包含的自定义逻辑.这工作正常,应用程序按预期运行.我遇到的问题是当我尝试配置我的测试模块以使用此HttpInterceptor类时,会引发错误.这是我的测试模块:

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
            ]
        });

    });
});
Run Code Online (Sandbox Code Playgroud)

我知道我需要在configureTestingModule方法中提供HttpInterceptor类,以使此测试起作用.不幸的是,这会导致错误.正如您所看到的,我正在使用useFactory自己创建HttpInterceptor的实例,并提供所有需要的依赖项(MockBackend,BaseRequestOptions,AuthService,GlobalEventsManager).我不确定为什么会导致错误?

我玩了一下,当我在ProductService构造函数中更改dependendy时:

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

    constructor(
        private _http: HttpInterceptor
    ) {

    }
Run Code Online (Sandbox Code Playgroud)

对此:

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

    constructor(
        private _http: Http
    ) {

    }
Run Code Online (Sandbox Code Playgroud)

然后在测试模块中提供核心Http模块,如此处所示,测试模块无误地工作.

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

这意味着将一个HttpInterceptor类的实例注入测试模块时出现问题,我无法弄清楚原因.谁能明白为什么会发生这种情况?