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'); }); } }
Solution. You need to import the routing module with this component to the root module of the feature.
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.
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.
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.
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 ] })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With