61

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!

4 Answers4

64

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.

s-gbz
  • 402
  • 8
  • 11
JP07
  • 649
  • 5
  • 3
  • Don't forget to make the same change in app.module.ts as well (Angular 5 context). – taylorswiftfan Nov 14 '18 at 01:14
  • but he has imported the HttpClientTestingModule in his .service.spec.ts, as it is shown above? –  May 29 '19 at 11:31
  • @Marius you also need to add it to imports array of TestBed configuration object as shown in the answer – Nikita Marinosyan Jul 03 '19 at 08:39
  • 1
    Hi JP07, I just want to ask that if I'm injecting `private changeDetector: ChangeDetectorRef` in constructor, then is it required to mock this service in spec file also. I'm asking this because I'm new to angular. I don't know. Please help. – Tanzeel Mar 16 '20 at 04:25
16

simply add it like this,

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientModule,
      ],
    }).compileComponents();
  });
M.Octavio
  • 1,780
  • 2
  • 25
  • 39
  • 5
    Thank you, this resolved my problem! Btw I do not like the angular way of testing because it is very shady - the fact that this is the 5-th stackoverflow topic for the problem I have tells me it is very complex to write these test the right way. I don't know if I just need to learn more about the angular test or other people are frustrated because their testing mechanism is blaah. – Combine Dec 03 '19 at 22:20
14

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.

R. Richards
  • 24,603
  • 10
  • 64
  • 64
3

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
      ]
SantoshK
  • 1,789
  • 16
  • 24