0

I am having a app.component.html file with button to navigate to another component called HomeComponent

<button (click)="nav()" id="nav">Navigate</button>
 <router-outlet></router-outlet>

My app.component.ts file

import { Component } from '@angular/core';
import { RouterModule,Router, Routes } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  constructor(private router: Router){

  }
  nav(){
    this.router.navigate(['/home']);
  }

}

and my app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { RouterModule, Routes,Router } from '@angular/router';


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([{ path: "", component: AppComponent}]),
    RouterModule.forChild([{ path: "home", component: HomeComponent}])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Here is my spec file app.component.spec.ts

import { TestBed, async, ComponentFixture, fakeAsync, tick,inject } from '@angular/core/testing';
import { By, BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { DebugElement } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { Router, RouterOutlet } from "@angular/router";
import { FormsModule } from "@angular/forms";
import { RouterTestingModule } from '@angular/router/testing';
import * as br from '@angular/platform-browser';


describe('Component:AppComponent', () => {
  let location, router;
  let mockRouter

  beforeEach(() => {
    mockRouter = {
      navigate: jasmine.createSpy('navigate')
    };
    TestBed.configureTestingModule({
      imports: [RouterTestingModule.withRoutes([
        { path: 'home', component: HomeComponent }
      ])],
      declarations: [AppComponent, HomeComponent]
    });
  });




  it('should go home', async(() => {
    let fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
     console.log(mockRouter.navigate);
    let component = TestBed.createComponent(AppComponent).componentInstance;
    component.nav();
    spyOn(component, 'nav');

    fixture.detectChanges();

    expect(mockRouter.navigate).toHaveBeenCalledWith(['/home']);

  }));
});

I am getting the result as enter image description here

2 Answers2

3

In order to create unit test case for router.navigate you can do something like this:

import { TestBed, async, ComponentFixture, fakeAsync, tick,inject } from '@angular/core/testing';
import { By, BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { DebugElement } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { Router, RouterOutlet } from "@angular/router";
import { FormsModule } from "@angular/forms";
import { RouterTestingModule } from '@angular/router/testing';
import * as br from '@angular/platform-browser';


describe('Component:AppComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      declarations: [AppComponent, HomeComponent]
    });
  });

  it('should go home', async(inject([Router], (router) => {
    spyOn(router, 'navigate'); //added a spy on router
    let fixture = TestBed.createComponent(AppComponent);
    let component = TestBed.createComponent(AppComponent).componentInstance;
    component.nav();
    expect(router.navigate).toHaveBeenCalled();
    expect(router.navigate).toHaveBeenCalledWith(['/home']);

  }));
});
Vishal Hasnani
  • 720
  • 7
  • 21
  • 1
    This worked for me but `async` is deprecated for removal in v12. Docs say to use `waitForAsync` from '@angular/core/testing' instead which also works for me. – Chris R Dec 07 '20 at 13:03
  • spyon navigate() method does not exist – cakePHP Aug 12 '21 at 12:03
0

You have spied on router but you haven't provided it to the testBed environment. Try adding

providers: [
   { provide: Router, useValue: mockRouter},
], 

after declarations.

Also you need not include RouterTestingModule since you are not clicking any links.

References:

https://stackoverflow.com/a/46342813/8558515

Angular 2 Unit Testing - Cannot read property 'root' of undefined

Sanju
  • 1,478
  • 2
  • 20
  • 41