0
votes

I'm a beginer in angular testing and my question may be part of 'best practice in angular testing'.

I'm looking for a method to include smallest module in testing and overide some part that need to me mocked.

Let say I've got a button component that need the Router to work. Its module is like so :

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MyButtonComponent } from './mybutton.component';
import { Router } from '@angular/router';
@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [
    MyButtonComponent,
  ],
  exports: [
    MyButtonComponent,
  ],
  providers: [
    Router,
  ]
})
export class MyButtonModule { }

Now I want to test it like so :

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { MyButtonModule } from './viewer-button.module';
import { RouterTestingModule } from '@angular/router/testing';

// Tests Begining
describe('ViewerButtonComponent', () => {
  let component: MyButtonComponent;
  let fixture: ComponentFixture<MyButtonComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        ViewerButtonModule,
        RouterTestingModule.withRoutes([]),
      ],
    })
    .compileComponents();

    fixture = TestBed.createComponent(MyButtonComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

  });

  it('#should create the component', () => {
    expect(component).toBeTruthy(' fail at creation');
  });
});

But the Router does no overide with RouterTestingModule imports. (got the Can't resolve all parameters for Router: (?, ?, ?, ?, ?, ?, ?, ?). error)

I know a better way for this example is only to declare MyButtonComponent, then imports RouterTestingModule but I'm asking if there is a way to do this with larger component without the NO_ERRORS_SCHEMAshallow thing.

For example:

 beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        // my childs component module
        MyChildComponentModule1,
        MyChildComponentModule2,
        ...
        MyChildComponentModuleX,

        //the modules that mock what needed (or use custom mock in the providers part)
        RouterTestingModule,
        HttpClientTestingModule,
        ....
        SomethingTestingModule
      ],
    })
    .compileComponents();

    fixture = TestBed.createComponent(MyButtonComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

  });

1

1 Answers

0
votes

The RouterTestingModule is for stubbing routing and navigation.

A few points here:

1) You shouldn't provide Router yourself in your widget module. Instead, you should add RouterModule.forRoot() to AppModule which will provide the Router service and its dependencies.

2) You shouldn't create mixed Angular modules, meaning don't provide and declare in a single Angular moudule.

3) Angular module import order matters. With this import order, RouterTestingModule's provider will override the Router provider from ViewButtonModule.

TestBed.configureTestingModule({
  imports: [
    ViewerButtonModule,
    RouterTestingModule.withRoutes([]),
  ],
});

4) You can always override a provider using the Angular testing module. For example

TestBed.overrideProvider(Router, { useValue: routerStub });

or

TestBed.configureTestingModule({
  providers: [
    { provide: Router, useValue: routerStub },
  ],
});

If you're interesting in learning more, you can keep my article Testing and Faking Angular Dependencies as a reference on those hard-to-remember details.

In 2020 I wrote these articles: