Ошибка при модульном тестировании HttpClientModule (Angular 4.3+)
Я изучаю новый Angular HttpClientModule и сталкиваюсь с необъяснимой ошибкой. Модуль достаточно новый, поэтому я пока не могу найти полезную информацию о том, как проводить модульное тестирование, и в официальной документации нет примеров.
Приложение содержит сервис с одним методом, который передает URL-адрес http.get
, Когда я вызываю этот метод в контексте браузера (иначе ng serve
), вызов http выполняется нормально. При вызове в контексте модульного теста я получаю следующую ошибку:
TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
Это минимальное приложение, созданное с помощью Angular CLI. Вот соответствующий код:
app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts:
import { Component, OnInit } from '@angular/core';
import { TestService } from './test.service'
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [TestService]
})
export class AppComponent {
title = 'app';
constructor(private testSvc: TestService) {}
ngOnInit() {
this.testSvc.executeGet('http://www.example.com');
}
}
test.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class TestService {
constructor(private http:HttpClient) {}
executeGet(url:string) {
this.http.get(url)
.subscribe(
data => console.log('success', data),
error => console.log('error', error)
);
}
}
test.service.spec.ts:
import { HttpClient, HttpHandler } from '@angular/common/http';
import { TestBed, inject } from '@angular/core/testing';
import { TestService } from './test.service';
describe('TestService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [HttpClient, HttpHandler, TestService]
});
});
it('should executeGet', inject([TestService], (svc: TestService) => {
expect(svc.executeGet).toBeDefined();
// this is where the 'undefined' error occurs
svc.executeGet('http://www.example.com');
}));
});
Любые указания или указатели очень ценятся.
2 ответа
Отсутствует импорт HttpClientModule
describe('TestService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [TestService]
});
});
it('should executeGet', () => {
const testService = TestBed.get(TestService);
expect(testService.executeGet).toBeDefined();
testService.executeGet('http://www.example.com');
}));
});
Недавно у меня возникла точно такая же проблема, когда в сообщении об ошибке говорится:
TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
Для меня источником этой ошибки было неправильное использование HttpInterceptor. Если вы также предоставляете собственный HttpInterceptor, убедитесь, что вы правильно его используете. В следующем фрагменте кода обратите внимание, как я пропустил возвращение Observable, Promise, Array, or Iterable
если состояние ошибки отличается от 401. По умолчанию undefined
возвращается intercept
метод вместо Observable, Promise, Array, or Iterable
так угловатые жалуются на это.
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).catch(err => {
if(err instanceof HttpErrorResponse) {
if(err.status === 401) {
this.store.dispatch(this.authAction.unauthorized(err));
return Observable.throw(err);
}
}
})
}
и исправление было следующим фрагментом кода.
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).catch(err => {
if(err instanceof HttpErrorResponse) {
if(err.status === 401) {
this.store.dispatch(this.authAction.unauthorized(err));
}
}
return Observable.throw(err); //Actually this line of code
})
}