title: Angular Testing - Mocking An InjectionToken
body: <p>I'm trying to test an Angular service that handles SignalR connections, which takes the code for SignalR as an InjectionToken.</p>
  
  <p>Here's the provider file:</p>
  
  <pre><code>// signalr-provider.ts
  
  import { InjectionToken } from '@angular/core';
  
  export const SIGNALR_TOKEN = new InjectionToken('signalR');
  
  export function signalRFactory() {
      return window['signalR'];
  }
  
  export const SIGNALR_PROVIDER = [ { provide: SIGNALR_TOKEN, useFactory: signalRFactory } ];
  </code></pre>
  
  <p>And here's the service:</p>
  
  <pre><code>// signalr-service.ts
  
  import { Injectable, Inject } from '@angular/core';
  
  import { SIGNALR_TOKEN } from './signalr-provider';
  import { HubConnection } from '@aspnet/signalr';
  import { environment } from '../../../environments/environment';
  
  @Injectable()
  export class SignalrService {
      private hubConnection: HubConnection;
      private baseUrl: string = environment.baseUrl;
  
      constructor(@Inject(SIGNALR_TOKEN) private signalR: any) {
          this.init();
      }
  
      init(): void {
          this.hubConnection = new this.signalR.HubConnectionBuilder().withUrl(`${this.baseUrl}/hubs/test`).build();
      }
  }
  </code></pre>
  
  <p>The token is provided in the app module like this:</p>
  
  <pre><code>// From app.module.ts
  
  @NgModule({
      declarations: [...],
      imports: [...],
      providers: [ SIGNALR_PROVIDER, SignalrService ],
      bootstrap: [ AppComponent]
  })
  export class AppModule {}
  </code></pre>
  
  <p>So far, I'm having no luck trying to mock the InjectionToken in my test file, and end up with a <code>NullInjectorError: No provider for InjectionToken signalR!</code> message every time.</p>
  
  <p>Here's my first attempt, returning a mocked object from the signalRFactory function with only the properties needed in the initial connection:</p>
  
  <pre><code>// signalr-service.spec.ts
  
  import { TestBed, async } from '@angular/core/testing';
  import { InjectionToken } from '@angular/core';
  
  import { SignalrService } from './signalr-service';
  
  const SIGNALR_TOKEN = new InjectionToken('signalR');
  
  function signalRFactory() {
      return {
          HubConnectionBuilder: () =&gt; {
              return {
                  withUrl: (url) =&gt; {
                      return {
                          build: () =&gt; {}
                      };
                  }
              };
          }
      };
  }
  
  const SIGNALR_PROVIDER = [ { provide: SIGNALR_TOKEN, useFactory: signalRFactory } ];
  
  describe('ConnectionService', () =&gt; {
      beforeEach(
          async(() =&gt; {
              TestBed.configureTestingModule({
                  providers: [ SIGNALR_PROVIDER, SignalrService ]
              });
          })
      );
  
      it('should exist', () =&gt; {
          const connectionService = TestBed.get(SignalrService);
          expect(connectionService).toBeTruthy();
      });
  });
  </code></pre>
  
  <p>In my second attempt, I assigned the mocked object to a variable:</p>
  
  <pre><code>import { TestBed, async } from '@angular/core/testing';
  import { InjectionToken } from '@angular/core';
  
  import { SignalrService } from './signalr-service';
  
  const SIGNALR_TOKEN = new InjectionToken('signalR');
  
  const SIGNALR_VALUE = {
      HubConnectionBuilder: () =&gt; {
          return {
              withUrl: (url) =&gt; {
                  return {
                      build: () =&gt; {}
                  };
              }
          };
      }
  };
  
  const SIGNALR_PROVIDER = [ { provide: SIGNALR_TOKEN, useValue: SIGNALR_VALUE } ];
  
  describe('ConnectionService', () =&gt; {
      beforeEach(
          async(() =&gt; {
              TestBed.configureTestingModule({
                  providers: [ SIGNALR_PROVIDER, SignalrService ]
              });
          })
      );
  
      it('should exist', () =&gt; {
          const connectionService = TestBed.get(SignalrService);
          expect(connectionService).toBeTruthy();
      });
  });
  </code></pre>
  
  <p>In my third attempt, I took out the SIGNALR_PROVIDER and tried to provide the value directly in the providers array by factory and by direct value:</p>
  
  <p>Direct value:</p>
  
  <pre><code>import { TestBed, async } from '@angular/core/testing';
  import { InjectionToken } from '@angular/core';
  
  import { SignalrService } from './signalr-service';
  
  const SIGNALR_TOKEN = new InjectionToken('signalR');
  
  const SIGNALR_VALUE = {
      HubConnectionBuilder: () =&gt; {
          return {
              withUrl: (url) =&gt; {
                  return {
                      build: () =&gt; {}
                  };
              }
          };
      }
  };
  
  describe('ConnectionService', () =&gt; {
      beforeEach(
          async(() =&gt; {
              TestBed.configureTestingModule({
                  providers: [ { provide: SIGNALR_TOKEN, useValue: SIGNALR_VALUE }, SignalrService ]
              });
          })
      );
  
      it('should exist', () =&gt; {
          const connectionService = TestBed.get(SignalrService);
          expect(connectionService).toBeTruthy();
      });
  });
  </code></pre>
  
  <p>Factory:</p>
  
  <pre><code>import { TestBed, async } from '@angular/core/testing';
  import { InjectionToken } from '@angular/core';
  
  import { SignalrService } from './signalr-service';
  
  const SIGNALR_TOKEN = new InjectionToken('signalR');
  
  function signalRFactory() {
      return {
          HubConnectionBuilder: () =&gt; {
              return {
                  withUrl: (url) =&gt; {
                      return {
                          build: () =&gt; {}
                      };
                  }
              };
          }
      };
  }
  
  describe('ConnectionService', () =&gt; {
      beforeEach(
          async(() =&gt; {
              TestBed.configureTestingModule({
                  providers: [ { provide: SIGNALR_TOKEN, useFactory: signalRFactory }, SignalrService ]
              });
          })
      );
  
      it('should exist', () =&gt; {
          const connectionService = TestBed.get(SignalrService);
          expect(connectionService).toBeTruthy();
      });
  });
  </code></pre>
  
  <p>Each attempt still gives me <code>NullInjectorError: No provider for InjectionToken signalR!</code> I'm stuck. There's obviously something I don't know about the InjectionToken. Could anyone point me in the right direction?</p>