Easy Angular Testing – RouterLink

The Angular RouterLink lets you link to specific routes in your app. In the example below, we’re setting ourselves up to write some very basic tests. Once we have the basics in place, we can wire up more code for deeper testing. The basic code below will also, while testing an app that uses the RouterLink directive, remove any errors related to using [routerlink].

Our first task is to create a stub directive for Angular’s RouterLink. Google’s out of the box stub is useful as a starting point, so we use that here. We create the aptly named RouterLinkStubDirective and place it in a folder accessible to any tests through our project that need to use it. In my case, this would be a ‘testing’ folder within the src level of our project.

// RouterLinkStubDirective
import { Directive, Input, HostListener } from '@angular/core';

// export for convenience.
export { RouterLink} from '@angular/router';

/* tslint:disable:directive-class-suffix */
@Directive({
  selector: '[routerLink]'
})
export class RouterLinkDirectiveStub {
  @Input('routerLink') linkParams: any;
  navigatedTo: any = null;

  @HostListener('click')
  onClick() {
    this.navigatedTo = this.linkParams;
  }
}

/// Dummy module to satisfy Angular Language service. Never used.
import { NgModule } from '@angular/core';

@NgModule({
  declarations: [
    RouterLinkDirectiveStub
  ]
})
export class RouterStubsModule {}


/*
Copyright Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

Our HTML is extremely simple and contains only two basic routerlinks. In this post, we’re not going to be concerned with queryParams or other such functionality.

<-- Router link test .html -->>
<a color="primary" [routerLink]="['/']">home</a>
<a color="primary" [routerLink]="['/activatedroutetest']"
  >Activated Route Test</a

Here is our project’s router module. Of course, we would replace RouterlinkTestComponent with the name of our actual component under test. If you notice here, neither our stub nor anything to do with our test is declared here. We do have a route to our actual component, which I’ve added with a path of ‘routerlinktest’.

// app router module
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RouterlinkTestComponent } from './routerlink-test/routerlink-test.component';

const routes: Routes = [
  { path: 'routerlinktest', component: RouterlinkTestComponent },
];

Finally we have our test spec. We’ve added in our RouterLinkDirectiveStub as an import, and have also added it to our declarations. At that point, it has taken over for the Angular RouterLink directive. This will give us an opportunity, as we build our tests, to remove all of the complexity of the Angular Routerlink. It also allows us to build a fixture and easily spy on our clickable routerlinks.

// routerlink spec
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { RouterlinkTestComponent } from './routerlink-test.component';

// This is added for our RouterLink test
import { RouterLinkDirectiveStub } from '../testing/router-link-stub.directive';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      // RouterLinkDirectiveStub is added for our RouterLink test
      declarations: [ RouterlinkTestComponent, RouterLinkDirectiveStub ]
    })
    .compileComponents();
  }));

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

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

The above example will remove any errors that describe a missing routerLink. As noted though, this doesn’t do any meaningful testing. For that we would build out a DebugElement and attach our RouterLink stub. We would then get each instance of our test directive. Finally we would use expect calls while pulling apart our Debug Element and test directive to check the links by triggering click events and examining the results.

At this point, you should have the basic testing functionality in place to remove any routerLink errors. You also now have the framework to start that deeper level testing, such as using spys and simulating click events, to get to more meaningful testing.

All of the code shown here, and more Angular tests, can be found in this GitHub repo.