Unit testing error HttpClientModule (Angular 4.3+)

I am learning the new Angular HttpClientModule and am running an unexplained error. The module is new enough that I can't find any useful information on how to unit test yet, and there are no examples in the official documentation.

The app contains a service with one method that passes the url http.get

. When I call this method in the browser context (aka ng serve

) the HTTP call is ok. When called in the context of a unit test, I get the following error:

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

This is a minimal application built with Angular CLI. Here's the relevant code:

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

      

Any guidance or pointers were greatly appreciated.

+3


source to share


2 answers


Importing HttpClientModule is missing

Here is a working example on plnkr



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

      

+1


source


I recently experienced the same problem which says the error:

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

For me, the source of this error was not using HttpInterceptor . If you provide a custom HttpInterceptor as well , make sure you use it correctly. In the following code snippet, notice how I missed returning Observable, Promise, Array, or Iterable

if the error status is different from 401. By default undefined

, the method returns intercept

instead Observable, Promise, Array, or Iterable

, which is why angular is complaining about that.



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

      

and the fix is ​​the following piece of code.

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

      

+3


source







All Articles