test - No provider for TranslateService

Viewed 9839

I'm running some tests using the ng test command and I get the following error message:

NullInjectorError: R3InjectorError(DynamicTestModule)[TranslateService -> TranslateService]: 
  NullInjectorError: No provider for TranslateService!

The test is:

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { TranslateTestingModule } from 'ngx-translate-testing';
import { CoreModule } from './core.module';

const ENGLISH_LANGUAGE = 'en';

describe('AppComponent', () => {

  let fixture: ComponentFixture<AppComponent>;
  let appComponent: AppComponent;

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    appComponent = fixture.componentInstance;
  });

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports: [
        CoreModule,
        TranslateTestingModule
          .withTranslations(ENGLISH_LANGUAGE, require('assets/i18n/en.json'))
          .withDefaultLanguage(ENGLISH_LANGUAGE)
      ],
    }).compileComponents();
  });

  it('should create the app', async(() => {
    expect(appComponent).toBeTruthy();
  }));

  it('should have as title', async(() => {
    appComponent.ngOnInit();
    fixture.whenStable().then(() => {
      expect(appComponent.testTitle).toEqual('app');
    })
  }));

});

And the component is:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  testTitle?: string;

  constructor(
    private translateService: TranslateService,
    private screenDeviceService: ScreenDeviceService
  ) {}

  public ngOnInit() {
    const subscription: Subscription = this.translateService.get('app.title').subscribe((text: string) => {
      this.afterLanguageResourcesLoaded();
      subscription.unsubscribe();
    });
  }

  private afterLanguageResourcesLoaded(): void {
    this.setAppMetaData();
  }

  private setAppMetaData(): void {
    this.screenDeviceService.setMetaData({
      title: this.translateService.instant('app.title'),
      description: this.translateService.instant('app.description')
    });
    this.testTitle = this.translateService.instant('app.title');
  }

}

I also tried importing the BrowserModule module:

imports: [
  BrowserAnimationsModule,

And I tried adding a TranslateService provider:

providers: [
  TranslateService
]

I finally tried having two member variables for the two services to be injected into the component constructor:

let translateService: TranslateService;
let screenDeviceService: ScreenDeviceService;

and providing them:

providers: [
  TranslateService,
  ScreenDeviceService
]

and getting them:

translateService = TestBed.get(TranslateService);
screenDeviceService = TestBed.get(ScreenDeviceService);

But nothing helped.

I'm under Angular 9.0.4

UPDATE: I ended up using the real translate service instead of the mocked one and had to kill the test runner and type in again the ng test command for my source code to be considered.

2 Answers

In your test spec.ts file you could add this type of import, with forRoot():

TranslateModule.forRoot()

An example:

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        TranslateModule.forRoot(),
        HttpClientTestingModule
      ],
      declarations: [ HomeComponent ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
    .compileComponents();
  }));

This because you haven't to test the TranslateModule too. This solution works to me.

In your test file:

  1. Add an import: import { TranslateService } from '@ngx-translate/core';
  2. Add TranslateService to providers in TestBed configuration: providers: [ TranslateService ]
Related