首页 文章

Angular4 HttpClient.get()何时返回undefined?

提问于
浏览
2

我试图在Angular 4中测试一个HttpInterceptor . 我发现当我调用HttpClient.get()时,它会出错

TypeError:您提供了“undefined”,其中包含了一个流 . 您可以提供Observable,Promise,Array或Iterable .

http.get('/ data')什么时候返回undefined?

Plunkr here

import { Injectable } from '@angular/core';
import { TestBed, async, inject } from '@angular/core/testing';
import { HttpClient, HttpClientModule, HttpHandler } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import 'rxjs/add/operator/toPromise';


describe('AppComponent', () => {
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule, HttpClientModule],
            providers: [ HttpClient, HttpHandler,
              // {
              //     provide: HTTP_INTERCEPTORS,
              //     useClass: AuthErrorHttpInterceptorService,
              //     multi: true
              // }
            ]
        }).compileComponents();
    }));



    it('adding header test', inject([HttpClient], (http: HttpClient) => {
        debugger;
        const httpMock = TestBed.get(HttpTestingController);

        // Make an HTTP GET request, and expect that it return an object
        // of the form {name: 'Test Data'}.
        http.get('/data')
            .subscribe(data => expect(data['name']).toEqual('Test Data'));

        // At this point, the request is pending, and no response has been
        // sent. The next step is to expect that the request happened.
        const req = httpMock.expectOne('/data');

        // If no request with that URL was made, or if multiple requests match,
        // expectOne() would throw. However this test makes only one request to
        // this URL, so it will match and return a mock request. The mock request
        // can be used to deliver a response or make assertions against the
        // request. In this case, the test asserts that the request is a GET.
        expect(req.request.method).toEqual('GET');

        // Next, fulfill the request by transmitting a response.
        req.flush({name: 'Test Data'});

        // Finally, assert that there are no outstanding requests.
        httpMock.verify();
    }));
});

TypeError:您提供了“undefined”,其中包含了一个流 . 您可以提供Observable,Promise,Array或Iterable .

编辑:我已经看到问题Error while unit testing HttpClientModule (Angular 4.3+)并导入了HttpClientModule但我仍然得到错误 . 此外,我不包括我的拦截器组件,直到我修复此错误,因此有问题不能存在 .

编辑: const req = httpMock.expectOne('/data'); 此行永远不会执行,因为错误是从上面的行引发的

编辑:解决方案是从providers数组中删除'HttpClient,HttpHandler'

1 回答

  • 1

    仅供参考,最终解决方案

    import { AuthErrorHttpInterceptorService } from './authErrorHttpInterceptor.service';
    import { TestBed, inject, fakeAsync, tick } from '@angular/core/testing';
    import { RouterTestingModule } from '@angular/router/testing';
    import { LoginComponent } from './../../routes/login/login.component';
    import { Router } from '@angular/router';
    import { HttpHandler, HttpRequest, HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
    import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
    import 'rxjs/add/operator/catch';
    import { FormsModule } from '@angular/forms';
    import { Location } from '@angular/common';
    
    describe('AuthErrorHttpInterceptorService', () => {
        beforeEach(() => {
            TestBed.configureTestingModule({
                declarations: [LoginComponent],
                imports: [HttpClientTestingModule, HttpClientModule,
                    RouterTestingModule.withRoutes([{ path: 'login', component: LoginComponent }]),
                    FormsModule
                ],
                providers: [
                    {
                        provide: HTTP_INTERCEPTORS,
                        useClass: AuthErrorHttpInterceptorService,
                        multi: true
                    },
                    Location
                ]
            });
        });
    
        // https://angular.io/guide/http#testing-http-requests
        it('subscribe should return the given data', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
            const myGet = http.get('/data');
            myGet.subscribe((data) => {
                expect(data['name']).toEqual('Test Data');
                expect(data['name']).not.toEqual('Test Datas');
            });
            const req = httpMock.expectOne('/data');
            expect(req.request.method).toEqual('GET');
            req.flush({ name: 'Test Data' });
            httpMock.verify();
        }));
    
        it('should redirect unauthorised requests to /api/data', inject([HttpClient, HttpTestingController], fakeAsync((http: HttpClient, httpMock: HttpTestingController) => {
            const myGet = http.get('/api/data');
            myGet.subscribe((data) => {
                expect(data['name']).toEqual('Test Data');
            }, (error) => {
                let router = TestBed.get(Router);
                let location = TestBed.get(Location);
                tick();
                expect(location.path()).toBe('/login');
            });
            const req = httpMock.expectOne('/api/data');
            expect(req.request.method).toEqual('GET');
            req.flush({ name: 'Test Data' }, { status: 401, statusText: 'Server Error' });
            httpMock.verify();
        })));
    
        it('should not redirect unauthorised requests to /api/authorization/data', inject([HttpClient, HttpTestingController], fakeAsync((http: HttpClient, httpMock: HttpTestingController) => {
            const myGet = http.get('/api/authorization/data');
            myGet.subscribe((data) => {
                expect(data['name']).toEqual('Test Data');
            }, (error) => {
                let router = TestBed.get(Router);
                let location = TestBed.get(Location);
                tick();
                expect(location.path()).toBe('');
            });
            const req = httpMock.expectOne('/api/authorization/data');
            expect(req.request.method).toEqual('GET');
            req.flush({ name: 'Test Data' }, { status: 401, statusText: 'Server Error' });
            httpMock.verify();
        })));
    
        it('should not redirect http: 200 requests to /api/data', inject([HttpClient, HttpTestingController], fakeAsync((http: HttpClient, httpMock: HttpTestingController) => {
            const myGet = http.get('/api/authorization/data');
            myGet.subscribe((data) => {
                expect(data['name']).toEqual('Test Data');
            }, (error) => {
                let router = TestBed.get(Router);
                let location = TestBed.get(Location);
                tick();
                expect(location.path()).toBe('');
            });
            const req = httpMock.expectOne('/api/authorization/data');
            expect(req.request.method).toEqual('GET');
            req.flush({ name: 'Test Data' }, { status: 200, statusText: 'success' });
            httpMock.verify();
        })));
    });
    

    拦截器

    import { Injectable, forwardRef } from '@angular/core';
    import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/do';
    import { Router } from '@angular/router';
    import { Inject } from '@angular/core';
    
    @Injectable()
    export class AuthErrorHttpInterceptorService implements HttpInterceptor {
        constructor(private router: Router) { }
        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            return next.handle(req).do(event => { }, err => {
                if (err instanceof HttpErrorResponse
                    && err.status === 401
                    && !err.url.match('/api/authorization/')
                    && err.url.match('/api/')) {
    
                    this.router.navigate(['login']);
                }
            });
        }
    }
    

相关问题