title: Karma + Jasmine + Angular 4 - NullInjectorError: No provider for HttpClient
body: <p>I have the following set of files.
  I am trying to run unit tests using karma and jasmine.
  Whenever I run 'ng test' I'm getting following error in karma page.
  <a href="https://i.stack.imgur.com/ULtow.jpg" rel="noreferrer"><img src="https://i.stack.imgur.com/ULtow.jpg" alt="enter image description here"></a></p>
  
  <pre><code>Error: StaticInjectorError(DynamicTestModule)[ConfigService -&gt; HttpClient]: 
    StaticInjectorError(Platform: core)[ConfigService -&gt; HttpClient]: 
      NullInjectorError: No provider for HttpClient!
      at _NullInjector.webpackJsonp../node_modules/@angular/core/esm5/core.js._NullInjector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1002:1)
      at resolveToken (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1300:1)
      at tryResolveToken (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1242:1)
      at StaticInjector.webpackJsonp../node_modules/@angular/core/esm5/core.js.StaticInjector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1110:1)
      at resolveToken (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1300:1)
      at tryResolveToken (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1242:1)
      at StaticInjector.webpackJsonp../node_modules/@angular/core/esm5/core.js.StaticInjector.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:1110:1)
      at resolveNgModuleDep (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:10854:1)
      at _createClass (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:10891:1)
      at _createProviderInstance$1 (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:10865:1)
  </code></pre>
  
  <p>app.module.ts</p>
  
  <pre><code>import { ConfigService } from './config-service.service';
  import { BrowserModule } from '@angular/platform-browser';
  import { NgModule, APP_INITIALIZER } from '@angular/core';
  import { FormGroup, FormsModule, FormControl, Validators, ReactiveFormsModule, FormBuilder } from '@angular/forms';
  import { RouterModule, Routes } from '@angular/router';
  import { HttpModule } from '@angular/http';
  import { StorageServiceModule} from 'angular-webstorage-service';
  import { LoadingBarHttpModule } from '@ngx-loading-bar/http';
  import { HttpClientModule } from "@angular/common/http";
  
  import { AppComponent } from './app.component';
  import { FooterComponent } from './footer/footer.component';
  import { ForgotPasswordComponent } from './forgot-password/forgot-password.component';
  import { ResetPasswordComponent } from './reset-password/reset-password.component';
  import { LoginPageComponent } from './login-page/login-page.component';
  import { ResetPasswordGuardGuard } from './reset-password-guard.guard';
  
  
  export function getMetaData(cs: ConfigService) {
    return () =&gt; cs.getMetaData();
  }
  const appRoutes:Routes = [
    {   path: '',
        component: LoginPageComponent
    },{
        path: 'resetPassword',
        canActivate: [ResetPasswordGuardGuard],
        component: ResetPasswordComponent
    },{
        path: 'login',
        component: LoginPageComponent
    },{
      path: 'forgotPassword',
      component: ForgotPasswordComponent
    }
  ]
  @NgModule({
    declarations: [
      AppComponent,
      FooterComponent,
      ForgotPasswordComponent,
      ResetPasswordComponent,
      LoginPageComponent
    ],
    imports: [
      BrowserModule,
      FormsModule,
      RouterModule.forRoot(appRoutes, {useHash: true}),
      HttpModule,
      StorageServiceModule,
      ReactiveFormsModule,
      LoadingBarHttpModule,
      HttpClientModule,
    ],
    providers: [
      ConfigService,
      ResetPasswordGuardGuard,
      { 
        provide: APP_INITIALIZER, 
        useFactory: getMetaData,
        deps: [ConfigService], 
        multi: true 
      },
    ],
    bootstrap: [AppComponent],
    exports: [RouterModule]
  })
  export class AppModule { }
  </code></pre>
  
  <p>config.service.ts</p>
  
  <pre><code>import { ForgotPasswordComponent } from './forgot-password/forgot-password.component';
  import { LoginPageComponent } from './login-page/login-page.component';
  import { Injectable, OnInit } from '@angular/core';
  import { HttpClient } from '@angular/common/http';
  
  @Injectable()
  export class ConfigService {
    private urls:object = {
      loginPage       : "/api/loginValidate",
      forgotPassword  : "/api/forgotPassword",
      resetPassword   : "/api/resetPassword",
      tokenLength     : 30,
      token           : "unique"
      };
    private metaData:object;
    private footer = {    client : {},    provider:{}  };
    private metaDataURL = "/api/getMetaData";
    constructor(private httpClient: HttpClient) {  }
    getMetaData(): Promise&lt;any&gt; {
      const promise = this.httpClient.get(this.metaDataURL)
        .toPromise()
        .then(data =&gt; {
          this.metaData = data;
          this.footer.client = this.metaData['companyDetails'][this.metaData['defaultSettings']]['client'];
          this.footer.provider = this.metaData['companyDetails'][this.metaData['defaultSettings']]['provider'];
          return data;
        });
      return promise;
    }
    getLogoUrl(){
      return this.metaData['companyDetails'][this.metaData['defaultSettings']]['imgURL'];
    }
    getFooter(){
      return this.footer;
    }
    //------------------- RESET PASS PAGE -------------------
    getLengthOfToken(){
      return this.urls["tokenLength"];
    }
    getResetPasswordToken(){
      return this.urls["token"];
    }
    getResetPassUrl(){
      return this.urls["resetPassword"];
  
    }
    //------------------- FORGOT PASS PAGE -------------------
    getForgotPassUrl(){
      return this.urls["forgotPassword"];
    }
    //------------------- LOGIN PASS PAGE -------------------
    getloginUrl(){
      return this.urls["loginPage"];
    }
  };
  </code></pre>
  
  <p>login-page.component.ts</p>
  
  <pre><code>    import { ConfigService } from './../config-service.service';
      import { Component, OnInit, AfterViewInit, ElementRef } from '@angular/core';
      import { Router } from '@angular/router';
      import { FormGroup,FormsModule, FormControl, Validators ,ReactiveFormsModule, FormBuilder } from '@angular/forms';
      import { Http, Response} from '@angular/http';
      import 'rxjs/add/operator/map';
      import {LOCAL_STORAGE, SESSION_STORAGE} from 'angular-webstorage-service';
      import { LoadingBarHttpModule } from '@ngx-loading-bar/http';
  
      @Component({
        selector: 'app-login-page',
        templateUrl: './login-page.component.html',
        styleUrls: ['./login-page.component.scss']
      })
      export class LoginPageComponent  {
        usernameRegex = new RegExp("[a-zA-Z0-9.-_]{1,}@[a-zA-Z.-]{2,}[.]{1}[a-zA-Z]{2,}");
        logoUrl:string;
        showInvalidCredError = false;
        showServerError = false;
        form: FormGroup;
        constructor(private fb:FormBuilder, private router:Router,private http: Http,private service: ConfigService) {
        console.log("login.comp");    
  
          this.form = fb.group({
            "username": ['', [Validators.required, Validators.minLength(2), Validators.pattern(this.usernameRegex)]],
            "password": ['', [Validators.required, Validators.minLength(6)]],
            "rememberMe": ['']
          });
          // this.logoUrl="assets/images/cerebra_logo.png";
          // service.getMetaData();
          this.logoUrl=this.service.getLogoUrl();
          if(localStorage.getItem("appCredsUsername") &amp;&amp; localStorage.getItem("appCredsPassword")){
            this.form.setValue(
              {  username   : localStorage.getItem("appCredsUsername"),
                 password   : localStorage.getItem("appCredsPassword"),
                 rememberMe : true
              }
            );
          }   
         }
        b64EncodeUnicode(str) {
              return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
                  function toSolidBytes(match, p1) {
              var temp:string = String.fromCharCode(+('0x' + p1));
                      return temp;
              }));
          }
        getData(param){                                           // used for making http calls
          return this.http.post(this.service.getloginUrl(),param).map((res: Response)=&gt; res.json());  
        }
        get username(){                                                  // to get username for form validation
          return this.form.get("username");
        }
        get password(){                                                  // to get password for form validation
          return this.form.get("password");
        }
        forgotPassword(){                                                // routing to forget password page
          this.router.navigate(['forgotPassword']);
        }
        hideError(){
          this.showInvalidCredError = false;
          this.showServerError = false;
        }
        checkAuth(){
          if(this.form.controls.username.status=='VALID' &amp;&amp; this.form.controls.password.status == 'VALID'){
            if(this.form.get("rememberMe").value == true){
              localStorage.setItem("appCredsUsername",this.username.value);
              localStorage.setItem("appCredsPassword",this.password.value);
              localStorage.setItem("appCredsRememberMe",'true');
            }
            else{
              localStorage.setItem("appCredsUsername","");
              localStorage.setItem("appCredsPassword","");
              localStorage.setItem("appCredsRememberMe",'false');
  
            }
            var param = {
              "username"  : this.username.value.toLowerCase(),
              "password"  : this.b64EncodeUnicode(this.password.value)
              };
            this.getData(param).subscribe(data =&gt; {
              if(data["status"]=="ERROR"){                                    // server down or something
                this.showServerError = true;
              }else if(data["status"] == "SUCCESS"){                          //success, got app name, will redirect now.
                sessionStorage.setItem("appToken",data["token"]);             //setting recived JWT token in session.
                location.href = data["pageUrl"];                              //Redirection Actual URL sent by API
              }else if(data["status"]=="FAILED"){                             //invalid username password entered
                this.showInvalidCredError = true;
              }
            });
          }
        }
      }
  
  login-page.component.spec.ts
  
  import { async, inject, ComponentFixture, TestBed } from '@angular/core/testing';
  import {ReactiveFormsModule, FormsModule} from "@angular/forms";
  import { Injectable } from '@angular/core';
  import { LoginPageComponent } from './login-page.component';
  import { RouterTestingModule } from '@angular/router/testing';
  import { MockBackend, MockConnection } from '@angular/http/testing';
  import { ConfigService } from './../config-service.service';
  import {
    Http, ResponseOptions,
    Response, BaseRequestOptions, ConnectionBackend, RequestOptions
  } from '@angular/http';
  import { HttpClientModule } from '@angular/common/http';
  
  var loginArray : object[] = [
    {username:"", password:"", IsValid:false},
    {username:"user1", password:"qwqwqwqw", IsValid:false},
    {username:"user1@cerebra", password:"", IsValid:false},
    {username:"user1@cerebra.com", password:"aaa", IsValid:false},
    {username:"user1cerebra.com", password:"aa", IsValid:false},
    {username:"user1cerebra.com", password:"qwqwqwqw", IsValid:false},
    {username:"user1@cerebra.com", password:"qwqwqwqw", IsValid:true},
    {username:"admin@cerebra.com", password:"qwqwqwqw", IsValid:true},  
  ];
  
  @Injectable()
  class validateMock {
    constructor(private _http: Http) {}
    getSomething(url) {
      return this._http.get(url).map(res =&gt; res.text());
    }
  }
  
  describe('LoginPageComponent', async() =&gt; {
    let component: LoginPageComponent;
    let fixture: ComponentFixture&lt;LoginPageComponent&gt;;
  
    beforeEach(() =&gt; {
      TestBed.configureTestingModule({
        imports : [
          ReactiveFormsModule, 
          FormsModule, 
          RouterTestingModule, 
          HttpClientModule],
        declarations: [LoginPageComponent],
        providers: [
          ReactiveFormsModule, 
          // BaseRequestOptions,
          // MockBackend,
          // BaseRequestOptions,
          ConfigService]
      }).compileComponents();
  
      fixture = TestBed.createComponent(LoginPageComponent);
      component = fixture.componentInstance;
    });
    //Mocking The HTTP Call and getting the Response
    it('should get Validation Response', async(inject([validateMock, MockBackend],
      (service: validateMock, backend: MockBackend) =&gt; {
        backend.connections.subscribe((conn: MockConnection) =&gt; {
          const options: ResponseOptions = new ResponseOptions({body:'Hola'});
          conn.mockRespond(new Response(options));
      });
  })));
    //Iteration over an Array to check all possible test cases
    for(let i = 0; i &lt; loginArray.length; i++){
      it("username:"+loginArray[i]['username']+", IsValid: "+loginArray[i]['IsValid'],() =&gt; {
        let userName = component.form.controls['username'];
        userName.setValue(loginArray[i]['username']);
        let password = component.form.controls['password'];
        password.setValue(loginArray[i]['password']);
        expect(component.form.valid).toBe(loginArray[i]['IsValid']);
      });
    }
  });
  </code></pre>
  
  <p>I have the above set of files.
  I am trying to run unit tests using karma and jasmine.
  Whenever I run 'ng test' I'm getting above error in karma page.
  Please help me resolve this issue. Thanks in advance:).</p>