Angular 5 service failing to pass unit tests with (NullInjectorError: No provider for HttpClient!)

AngularUnit TestingTypescriptAngular5

Angular Problem Overview


I keep getting the following errors when running unit tests

Error: StaticInjectorError(DynamicTestModule)[ApiService -> HttpClient]: 
	  StaticInjectorError(Platform: core)[ApiService -> HttpClient]: 
	    NullInjectorError: No provider for HttpClient!

api.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ApiService {

  constructor(private http: HttpClient) { }
  url = './assets/data.json';

  get() {
    return this.http.get(this.url);
  }
}

api.service.spec.ts

import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

import { ApiService } from './api.service';

describe('ApiService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
      ],
      providers: [
        ApiService,
      ],
    });
  });

  it('should get users', inject([HttpTestingController, ApiService],
      (httpMock: HttpTestingController, apiService: ApiService) => {
        expect(apiService).toBeTruthy();
      }
    )
  );
});

I don't understand what is going wrong as I have included HttpClient into api.service.ts, the service works in the browser.

This is directly called in a component called MapComponent, and that is called inside HomeComponent.

Chrome 63.0.3239 (Mac OS X 10.13.3) HomeComponent expect opened to be false FAILED
	Error: StaticInjectorError(DynamicTestModule)[ApiService -> HttpClient]: 
	  StaticInjectorError(Platform: core)[ApiService -> HttpClient]: 
	    NullInjectorError: No provider for HttpClient!

Angular Solutions


Solution 1 - Angular

The reason for "NullInjectorError: No provider for HttpClient!" are unresolved dependencies. In this case the lack of a HttpClientModule.

In your .service.spec.ts file add

  imports: [
        HttpClientTestingModule,
    ],

You might notice that I wrote HttpClientTestingModule instead of HttpClientModule. The reason is that we don't want to send actual http requests, but rather use a Mock API of the test framework.

Solution 2 - Angular

simply add it like this,

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientModule,
      ],
    }).compileComponents();
  });

Solution 3 - Angular

Try wrapping your inject in an async, like below:

import { TestBed, async, inject } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { ApiService } from './api.service';

describe('ApiService', () => {
    beforeEach(() => {
      ...
    });    

  it(`should create`, async(inject([HttpTestingController, ApiService],
    (httpClient: HttpTestingController, apiService: ApiService) => {
      expect(apiService).toBeTruthy();
  })));

});

Don't forget to import async from @angular/core/testing.

I have had good success with this. It's the only different from your unit tests and mine where I use HttpClientTestingModule.

Solution 4 - Angular

I have imports HttpClientModule and HttpClientTestingModule modules which resoved my issues.

import { HttpClientTestingModule } from '@angular/common/http/testing';
import {HttpClientModule} from '@angular/common/http';

  imports: [
        HttpClientModule,
        HttpClientTestingModule
      ]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser6885115View Question on Stackoverflow
Solution 1 - AngularJP07View Answer on Stackoverflow
Solution 2 - AngularM.OctavioView Answer on Stackoverflow
Solution 3 - AngularR. RichardsView Answer on Stackoverflow
Solution 4 - AngularSantoshKView Answer on Stackoverflow