Search code examples
angulardependency-injectionscopejasmineangular-services

How to replace component-scoped service with spy object in Angular 6?


Currently I'm (Context: I am Angular beginner) developing a simple login-screen in a larger project with Angular 6 also using jasmine-tests. For the communication with the backend we use websockets which connect to different endpoints. For that reason I have to define component-scoped providers for two services:

// user-password-form.component.ts
@Component({
  selector: 'app-user-password-form',
  templateUrl: './user-password-form.component.html',
  styleUrls: ['./user-password-form.component.scss'],
  providers: [WebSocketService, AuthenticationService]
})

Now I want to test some functionality of user-password-form.component.ts by mocking AuthenticationService which uses WebSocketService. WebSocketService is also used by different other Services. The user-password-form.component only uses AuthenticationService, but due to the hierarchic DI, I also have to provide the WebSocketService at the component scope in order to receive an own instance.

Now, with jasmine, I want to test the functionality of the component by defining the following spec

const authServiceSpy
    = jasmine.createSpyObj('AuthenticationService', ['authenticate']);


  beforeEach(() => {

    TestBed.configureTestingModule({
      declarations: [UserPasswordFormComponent],
      providers: [LoggerService, FormBuilder,
        {provide: AuthenticationService, useValue: authServiceSpy}
      ],
      imports: [RouterModule],
      schemas: [NO_ERRORS_SCHEMA]
    })

However, in this case the spy isn't injected instead of the real authenticationService. Consequently, I am not able to run the following line:

expect(authService.authenticate.calls.mostRecent().args[0]).toEqual(authObj);

How can I force the Injection-mechanism to use the spyObject instead of the real AuthenticationService for the purpose of unit testing?


Solution

  • Your approach cannot work, because you replace the AuthService at the TestBed level, and the service is provided at the component level.

    You can completely replace the provider with TestBed.overrideProvider.

    Try this:

    TestBed.overrideProvider(AuthenticationService, { useValue: authServiceSpy });
    

    Also, make sure to call TestBed.compileComponents() after overriding the provider.