gentlyawesome
gentlyawesome

Reputation: 172

Failing test after adding Service with HTTPClient

I'm stuck at this problem where I get an error in my test when I add my BackendService to my DashboardComponent's contructor:

Error: StaticInjectorError(DynamicTestModule)[BackendService -> HttpClient]: StaticInjectorError(Platform: core)[BackendService -> HttpClient]:

NullInjectorError: No provider for HttpClient!

I have backend.service.ts where I have this:

  1 import { Injectable } from '@angular/core';
  2 import { HttpClient } from '@angular/common/http';
  3 import { Observable } from 'rxjs';
  4 import { environment } from '../environments/environment';
  5 
  6 @Injectable({
  7   providedIn: 'root'
  8 })  
  9 export class BackendService {
 10 
 11   constructor(private http: HttpClient) { }
 12 
 13   getUsers() : Observable<any> {
 14     return this.http.get<any>(`${environment.api}/api/users`);
 15   }   
 16 
 17 }

The backend.service.spec.ts is this:

 1 import { TestBed, inject, async } from '@angular/core/testing';
  2 import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
  3 import { environment } from '../environments/environment';
  4 
  5 import { BackendService } from './backend.service';
  6 
  7 describe('BackendService', () => {
  8   let service : BackendService;
  9   let backend : HttpTestingController;
 10   
 11   beforeEach(() => {
 12     TestBed.configureTestingModule({
 13       imports : [HttpClientTestingModule],
 14       providers: [BackendService]
 15     });
 16   });
 17   
 18   it('should be created', inject([HttpTestingController, BackendService], (backend: HttpTestingController, service: BackendService) => {
 19     expect(service).toBeTruthy();
 20   }));
 21   
 22   it('should get users', inject([HttpTestingController, BackendService], (backend: HttpTestingController, service: BackendService) => {
 23     service.getUsers().subscribe();
 24     const req = backend.expectOne(`http://localhost:4000/api/users`);
 25     expect(req.request.method).toEqual('GET');
 26     backend.verify();
 27   }));
 28 });

My DashboardComponent

  1 import { Component, OnInit } from '@angular/core';
  2 import { BackendService } from '../backend.service';
  3 
  4 @Component({
  5   selector: 'app-dashboard',
  6   templateUrl: './dashboard.component.html',
  7   styleUrls: ['./dashboard.component.css']
  8 })  
  9 export class DashboardComponent implements OnInit {
 10       
 11   constructor(private backend : BackendService) { } // This makes the  error
 12   
 13   ngOnInit() {
 14   }
 15     
 16 } 

The dashboard.component.spec.ts

  1 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
  2 import { DashboardComponent } from './dashboard.component';
  3 
  4 describe('DashboardComponent', () => {
  5   let component: DashboardComponent;
  6   let fixture: ComponentFixture<DashboardComponent>;
  7 
  8   beforeEach(async(() => {
  9     TestBed.configureTestingModule({
 10       declarations: [ DashboardComponent ]
 11     })
 12     .compileComponents();
 13   }));
 14 
 15   beforeEach(() => {
 16     fixture = TestBed.createComponent(DashboardComponent);
 17     component = fixture.componentInstance;
 18     fixture.detectChanges();
 19   });
 20 
 21   it('should create', () => {
 22     expect(component).toBeTruthy();
 23   });
 24 });

This is my app.moudule.ts

    1 import { BrowserModule } from '@angular/platform-browser';
    2 import { NgModule } from '@angular/core';
    3 import { HttpClientModule, HttpClient } from '@angular/common/http';
    4 
    5 import { AppRoutingModule, routingComponents } from './app-routing.module';
    6 import { AppComponent } from './app.component';
    7 
    8 @NgModule({
    9   declarations: [
   10     AppComponent,
   11     routingComponents
   12   ],
   13   imports: [
   14     BrowserModule,
   15     HttpClientModule,
   16     AppRoutingModule
   17   ],
   18   providers: [],
   19   bootstrap: [AppComponent]
   20 })
   21 export class AppModule { }
                                      

Upvotes: 0

Views: 1226

Answers (1)

R. Richards
R. Richards

Reputation: 25161

This is what your dashboard.component.spec.ts should look like in the end.

import { BackendService } from './../backend.service';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

import { DashboardComponent } from './dashboard.component';

describe('DashboardComponent', () => {
  let component: DashboardComponent;
  let fixture: ComponentFixture<DashboardComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DashboardComponent ],
      providers: [BackendService],
      imports: [HttpClientModule, HttpClientTestingModule]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DashboardComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Since the component depends on a service, which in turn depends on the HttpClient, you need to import the HttpClient testing modules that Angular makes available. Then, you need to add those things to the providers and imports arrays in the TestBed.configureTestingModule call. This makes all the HttpClient stuff available to the service you need.

I just coded this, tested it, and the tests succeeded.

This same pattern would apply to any component specs where the component depends on services that use HttpClient.

Upvotes: 2

Related Questions