Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Jasmine Can't bind to 'routerLink' since it isn't a known property of 'a'

I'm creating a unit test for my Navbar Component and I'm getting an error:

Can't bind to 'routerLink' since it isn't a known property of 'a'

Navbar Component TS

import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { NavActiveService } from '../../../services/navactive.service'; import { GlobalEventsManager } from '../../../services/GlobalEventsManager';  @Component({   moduleId: module.id,   selector: 'my-navbar',   templateUrl: 'navbar.component.html',   styleUrls:['navbar.component.css'],   providers: [NavActiveService] }) export class NavComponent {   showNavBar: boolean = true;    constructor(private router: Router,               private navactiveservice:NavActiveService,               private globalEventsManager: GlobalEventsManager){      this.globalEventsManager.showNavBar.subscribe((mode:boolean)=>{       this.showNavBar = mode;     });    }  } 

Navbar Component Spec

import { ComponentFixture, TestBed, async } from '@angular/core/testing';     import { NavComponent } from './navbar.component'; import { DebugElement }    from '@angular/core'; import { By }              from '@angular/platform-browser'; import { Router } from '@angular/router';  export function main() {     describe('Navbar component', () => {          let de: DebugElement;         let comp: NavComponent;         let fixture: ComponentFixture<NavComponent>;         let router: Router;          // preparing module for testing         beforeEach(async(() => {             TestBed.configureTestingModule({                 declarations: [NavComponent],             }).compileComponents().then(() => {                  fixture = TestBed.createComponent(NavComponent);                 comp = fixture.componentInstance;                 de = fixture.debugElement.query(By.css('p'));              });         }));           it('should create component', () => expect(comp).toBeDefined());   /*        it('should have expected <p> text', () => {             fixture.detectChanges();             const h1 = de.nativeElement;             expect(h1.innerText).toMatch(" ");         });*/       }); } 

I realize that I need to add router as a spy, but if I add it as a SpyObj and declare it as a provider I get the same error.

Is there a better way for me to add fix this error?

EDIT: Working Unit Test

Built this unit test based on the answer:

import { ComponentFixture, TestBed, async  } from '@angular/core/testing'; import { NavComponent } from './navbar.component'; import { DebugElement }    from '@angular/core'; import { By }              from '@angular/platform-browser'; import { RouterLinkStubDirective, RouterOutletStubComponent } from '../../../../test/router-stubs'; import { Router } from '@angular/router'; import { GlobalEventsManager } from '../../../services/GlobalEventsManager'; import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared.module';   export function main() {     let comp: NavComponent;     let fixture: ComponentFixture<NavComponent>;     let mockRouter:any;     class MockRouter {         //noinspection TypeScriptUnresolvedFunction         navigate = jasmine.createSpy('navigate');     }      describe('Navbar Componenet', () => {          beforeEach( async(() => {             mockRouter = new MockRouter();             TestBed.configureTestingModule({                 imports: [ SharedModule ]             })              // Get rid of app's Router configuration otherwise many failures.             // Doing so removes Router declarations; add the Router stubs                 .overrideModule(SharedModule, {                     remove: {                         imports: [ RouterModule ],                      },                     add: {                         declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ],                         providers: [ { provide: Router, useValue: mockRouter }, GlobalEventsManager ],                     }                 })                  .compileComponents()                  .then(() => {                     fixture = TestBed.createComponent(NavComponent);                     comp    = fixture.componentInstance;                 });         }));          tests();     });           function tests() {             let links: RouterLinkStubDirective[];             let linkDes: DebugElement[];              beforeEach(() => {                 // trigger initial data binding                 fixture.detectChanges();                  // find DebugElements with an attached RouterLinkStubDirective                 linkDes = fixture.debugElement                     .queryAll(By.directive(RouterLinkStubDirective));                  // get the attached link directive instances using the DebugElement injectors                 links = linkDes                     .map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective);             });              it('can instantiate it', () => {                 expect(comp).not.toBeNull();             });              it('can get RouterLinks from template', () => {                 expect(links.length).toBe(5, 'should have 5 links');                 expect(links[0].linkParams).toBe( '/', '1st link should go to Home');                 expect(links[1].linkParams).toBe('/', '2nd link should go to Home'); expect(links[2].linkParams).toBe('/upload', '3rd link should go to Upload');                 expect(links[3].linkParams).toBe('/about', '4th link should to to About');                 expect(links[4].linkParams).toBe('/login', '5th link should go to Logout');             });              it('can click Home link in template', () => {                 const uploadLinkDe = linkDes[1];                 const uploadLink = links[1];                  expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet');                  uploadLinkDe.triggerEventHandler('click', null);                 fixture.detectChanges();                  expect(uploadLink.navigatedTo).toBe('/');             });               it('can click upload link in template', () => {                 const uploadLinkDe = linkDes[2];                 const uploadLink = links[2];                  expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet');                  uploadLinkDe.triggerEventHandler('click', null);                 fixture.detectChanges();                  expect(uploadLink.navigatedTo).toBe('/upload');             });              it('can click about link in template', () => {                 const uploadLinkDe = linkDes[3];                 const uploadLink = links[3];                  expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet');                  uploadLinkDe.triggerEventHandler('click', null);                 fixture.detectChanges();                  expect(uploadLink.navigatedTo).toBe('/about');             });              it('can click logout link in template', () => {                 const uploadLinkDe = linkDes[4];                 const uploadLink = links[4];                  expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet');                  uploadLinkDe.triggerEventHandler('click', null);                 fixture.detectChanges();                  expect(uploadLink.navigatedTo).toBe('/login');             });         } } 
like image 687
Bhetzie Avatar asked Nov 22 '16 20:11

Bhetzie


People also ask

Can't bind to Routerlink since it isn't a known property?

Solution. You need to import the routing module with this component to the root module of the feature.

Can't bind to Routerlink since it isn't a known property of a angular test?

the reason is that you probably did not include RouterModule to your @NgModule in imports section. Important thing is this needs to be included in every module where you are using Router link or any other router feature.

Which angular package is used to route to URL?

Generate an application with routing enabledlink The following command uses the Angular CLI to generate a basic Angular application with an application routing module, called AppRoutingModule , which is an NgModule where you can configure your routes.

What is routerLinkActiveOptions exact true?

With routerLinkActiveOptions you can pass a javascript object {exact:true} to direct Angular to make link active only when exact path matches. With this configuration change 'Home' menu will only be highlighted when it is selected, as soon as you move away from this option it won't remain highlighted anymore.


1 Answers

Just import RouterTestingModule in TestBed.configureTestingModule of your components spec.ts file

Eg:

import { RouterTestingModule } from '@angular/router/testing';   TestBed.configureTestingModule({   imports: [RouterTestingModule],   declarations: [ ComponentHeaderComponent ] }) 
like image 190
Adrita Sharma Avatar answered Sep 20 '22 14:09

Adrita Sharma