Когда Angular4 HttpClient.get() возвращает неопределенное значение?
Я пытаюсь проверить HttpInterceptor в Angular 4. Я обнаружил, что при вызове HttpClient.get() происходит ошибка
Ошибка типа: вы указали "неопределенное" там, где ожидался поток. Вы можете предоставить Observable, Promise, Array или Iterable.
Когда http.get('/data') возвращает undefined?
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();
}));
});
Ошибка типа: вы указали "неопределенное" там, где ожидался поток. Вы можете предоставить Observable, Promise, Array или Iterable.
Редактировать: Я видел вопрос об ошибке при модульном тестировании HttpClientModule (Angular 4.3+) и импортированных HttpClientModule, но я все еще получаю ошибку. Также я не включаю свой компонент-перехватчик, пока я не исправлю эту ошибку, поэтому там не может быть проблемы.
Редактировать: const req = httpMock.expectOne('/data');
эта строка никогда не выполняется, потому что ошибка выдается из строки выше
Изменить: решение было удалить "HttpClient, HttpHandler" из массива провайдеров
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']);
}
});
}
}