Arun G
Arun G

Reputation: 264

How to do unit testing for getCurrentNavigation().extras.state in angular 7

I am trying to write unit test for getCurrentNavigation().extras.state using jasmine.

To solve the issue, I have tried to spy this router method.

My component file,

@Component({
  selector: 'app-location-list',
  templateUrl: './location-list.component.html',
  styleUrls: ['./location-list.component.scss']
})
export class LocationListComponent implements OnInit{

  locationId;
  locationName;
  constructor(private activatedRoute: ActivatedRoute, private router: Router) {
    if (this.router.getCurrentNavigation().extras.state) {
      this.locationId = this.router.getCurrentNavigation().extras.state.locationId;
    }
    if (this.router.getCurrentNavigation().extras.state) {
      this.locationName = this.router.getCurrentNavigation().extras.state.locationName;
    }
  }
  ngOnInit() { }
}

My Spec file,

describe('LocationListComponent ', () => {
  let component: LocationListComponent ;
  let fixture: ComponentFixture<LocationListComponent >;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        LocationListComponent 
      ],
      providers: []
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LocationListComponent );
    component = fixture.componentInstance;
    spyOn(Router.prototype, 'getCurrentNavigation').and.returnValues({ 'extras': { 'state': { 'locationId': 100, 'locationName': "UK" } } });
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

But I'm getting the following error,

TypeError: Cannot read property 'extras' of null

Can anyone help me to resolve this issue. I'm using Angular 7.2

Upvotes: 20

Views: 12722

Answers (4)

Aakash Goplani
Aakash Goplani

Reputation: 1354

Unit testing for router.getCurrentNavigation() can be done in 3 easy steps:

  1. Create mock router object:

    const mockRouter = {
      getCurrentNavigation: jasmine.createSpy('getCurrentNavigation')
    };
    
  2. Inject this in providers array:

    providers: [{ provide: Router, useValue: mockRouter }]
    
  3. Return the desired mocked value in the beforeEach() function

    mockRouter.getCurrentNavigation.and.returnValue({
      extras: {
        state: {
          test: ''
        }
      }
    });
    

Upvotes: 1

Bhavin
Bhavin

Reputation: 1208

If we try to use both RouterTestingModule and {provide: Router, useClass: RouterStub} it will throw error of cannot read property 'root' of undefined

So we can directly create spy for Route and return value of it

describe('LocationListComponent', () => {
  let component: LocationListComponent ;
  let fixture: ComponentFixture<LocationListComponent>;
  let router: jasmine.SpyObj<Router>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        LocationListComponent 
      ],
    })
      .compileComponents();
  }));

  beforeEach(() => {
    router = TestBed.get(Router);
    spyOn(router, 'getCurrentNavigation').and.returnValue({ extras: { state: { message: 'msg'} } } as any);
    fixture = TestBed.createComponent(LocationListComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Upvotes: 21

Shashank Vivek
Shashank Vivek

Reputation: 17514

You can easily do it using stub & useClass which can be reused at other spec files as well if you can create it in separate file and export class RouterStub , try:

In spec file create a stub which will have same method as Router:

class RouterStub{
 getCurrentNavigation(){
   return {
      extras: {
         state:{
           locationId: 'someId',
           locationName: 'someName'
         }
       }
     }
   }
}

and in beforeEach() block:

describe('LocationListComponent ', () => {
  let component: LocationListComponent ;
  let fixture: ComponentFixture<LocationListComponent >;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        LocationListComponent 
      ],
      providers: [ {provide: Router, useClass: RouterStub}]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LocationListComponent );
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Upvotes: 16

Siddhartha Gupta
Siddhartha Gupta

Reputation: 1158

You need to get the router instance from fixture

router = fixture.debugElement.injector.get(Router);

Upvotes: -2

Related Questions