Unit testing a component that uses the Router, in Angular2. angular2 , webpack , testing , import https://octoperf.com/blog/2016/03/31/angular2-router-and-unit-testing/ OctoPerf ZI Les Paluds, 276 Avenue du Douard, 13400 Aubagne, France +334 42 84 12 59 contact@octoperf.com Development 414 2021-01-04

Unit testing in Angular2

OctoPerf is JMeter on steroids!
Schedule a Demo

Unit tests in Angular2 with Karma

To follow up on my first article about Angular2 I want to unit test our Login component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import {Component} from 'angular2/core';
import {AuthenticationService} from '../services/authentication';
import {Router} from 'angular2/router';

@Component({
  selector: 'login',
  providers: [ ],
  directives: [ ],
  pipes: [ ],
  styles: [ require('./login.css') ],
  template: require('./login.html')
})
export class Login {
  private credentials: string = '';

  constructor(private authService: AuthenticationService, private router: Router) {
  }

  onSignIn(){
    this.authService.setCredentials(this.credentials);
    this.router.navigate(['Home']);
  }
}

The sample project comes with karma configured and some tests already written. So it’s straightforward to create a new unit test for our component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import {
  it,
  inject,
  injectAsync,
  describe,
  beforeEachProviders,
  TestComponentBuilder
} from 'angular2/testing';

import {Component, provide} from 'angular2/core';
import {AuthenticationService} from '../services/authentication';
import {Router} from 'angular2/router';

import {Login} from './login';

describe('Login', () => {
  beforeEachProviders(() => [
    Login,
    AuthenticationService
  ]);

  it('should set credentials and redirect on sign in', inject([ Login, AuthenticationService, Router], (login, auth, router) => {
    [...]
  }));
});

Mocking services

The hard part is to mock the Router Angular2 service. Indeed if we do not provide a Router implementation karma fails with the following error:

1
2
3
4
5
FAILED TESTS:
  Login
    ✖ should set credentials and redirect on sign in
      PhantomJS 2.1.1 (Linux 0.0.0)
    Failed: No provider for Router! (Login -> Router)

A quick googling tells us that we need to provide many Router related services:

1
2
3
4
5
6
beforeEachProviders(() => [
 ROUTER_PROVIDERS,
 provide(APP_BASE_HREF, {useValue: '/'}),
 provide(ROUTER_PRIMARY_COMPONENT, {useValue: Login}),
 provide(ApplicationRef, {useClass: MockApplicationRef}
]);

This may be a bit cumbersome in my case, and I preferred to provide a mock object instead of the real Router:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
describe('Login', () => {
  beforeEachProviders(() => [
    Login,
    AuthenticationService,
    provide(Router, {useValue: jasmine.createSpyObj('Router', ['navigate'])})
  ]);

  it('should set credentials and redirect on sign in', inject([ Login, AuthenticationService, Router], (login, auth, router) => {
    login.secretKey = 'test';
    spyOn(auth, 'setCredentials');
    login.onSignIn();
    expect(config.setCredentials).toHaveBeenCalledWith('test');
    expect(router.navigate).toHaveBeenCalledWith(['Home']);
  }));
});

This may be done with any service: we could have injected a spy AuthenticationService object instead of only spying on its setCredentials() method.

Also I think the syntax to write unit tests is much shorter in Angular2 than in AngularJS.

Unit testing in Angular2
Tags:
Share:
Comments (2)
Want to become a super load tester?
OctoPerf Superman