Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullInjectorError: StaticInjectorError(DynamicTestModule) When Testing in Angular 2

I'm brand new to Angular2 and trying to write a test in the app.component.spec.ts file. My application is relatively simple, besides the fact that it imports LoginComponent and LogoutComponent from a 3rd party library (written by coworkers). The components are used in a route login or logout respectively right now, pretty simple stuff. Running ng serve compiles ok and the application runs "smoothly". Running ng test, however, gives me this error:

NullInjectorError: StaticInjectorError(DynamicTestModule)[LogoutComponent -> SessionService]: 
  StaticInjectorError(Platform: core)[LogoutComponent -> SessionService]: 
    NullInjectorError: No provider for SessionService!

LogoutComponent is imported from a different project. Does this error mean I need to go into that project and make some changes, or am I supposed to be mocking SessionService somehow in my project?

Spec code:

import {} from 'jasmine';
import {async, TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {AuthErrorStateService, LogoutComponent} from '@custom-library';

import {AppComponent} from './app.component';
import {AppErrorStateService} from './core/error-states/app-error-state.service';
import {TopNavComponent} from './core/top-nav/top-nav.component';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed
        .configureTestingModule({
          imports: [RouterTestingModule],
          providers: [
            AppErrorStateService, AuthErrorStateService
          ],
          declarations: [AppComponent, TopNavComponent, LogoutComponent],
        })
        .compileComponents();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'My App'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app.title).toEqual('My App');
  });

  it('should render title in a h1 tag', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('h1').textContent).toEqual('Welcome to My App!');
  });
});
like image 675
Ryan Sperzel Avatar asked Mar 01 '19 20:03

Ryan Sperzel


1 Answers

The problem is declaring multiple components in TestBed like so

 declarations: [AppComponent, TopNavComponent, LogoutComponent]

results in multiple components being instantiated when the test calls compileComponents(). When that happens, each component in the declarations array needs its dependencies declared in the providers array to complete instantiation. One of the declared components depends on SessionService, but that service is not present in providers, so you get the NullInjectorError.

There are two solutions to this:

  • only declare one component in the declarations array and add schemas: [ CUSTOM_ELEMENTS_SCHEMA ] to the TestBed configuration object
  • continue to declare multiple components and add all the dependencies (or a mock thereof) for each component to the providers array
like image 53
The Head Rush Avatar answered Sep 21 '22 07:09

The Head Rush