Unit testing

with

Karma and Jasmine

 

Contents

  • Building and running unit tests
  • Basic blocks and structures
  • Loading fixtures
  • Unit testing services
  • Unit testing directives
  • Unit testing controllers
  • Mocking back-end responses
  • Spies
  • Links

Building and running unit tests

$ gulp build

Build project:

$ gulp test

Run tests:

Run once:

$ gulp test-dev

Watch changes:

Basic blocks and structures

  • describe()
  • module()
  • beforeEach()
  • inject()
  • it()
  • expect()

There are six most commonly used structures and blocks:

Grouping tests by topic:

describe(`Name of group or a module`, () => {
    ...
});

Importing AngularJS modules and dependencies:

module('app.settings');

Executing actions before each test:

beforeEach(() => {
    module('app.service');
});

Injecting services for further use in tests (underscore

annotation):

let $rootScope;
let customService;

inject((_$rootScope_, _customService_) => {
    $rootScope = _$rootScope_;
    customService = _customService_;
});

Test case blocks:

it(`Should show a test block example.`, () => {
    ...
});

Assertion of a value:

it(`Should return 'Hello world'`, () => {
    let ahoy = 'Hello world';

    expect(ahoy).toBe('Hello world'); // will pass
});

Available assertion matchers:

.toBe()
  .toBeCloseTo()
  .toBeDefined()
  .toBeFalsy()
  .toBeGreaterThan()
  .toBeGreaterThanOrEqual()
  .toBeLessThan()
  .toBeLessThanOrEqual()
  .toBeNaN()
  .toBeNull()
  .toBeTruthy()
  .toBeUndefined()
.toContain() 
.toEqual()
.toHaveBeenCalled()
  .toHaveBeenCalledTimes()
  .toHaveBeenCalledWith()
.toMatch()
.toThrow()
.toThrowError()

Example test case:

describe('Reverse filter', () => {
  let $filter;
  const timezones = [
    '(GMT-11) Niue Time',
    '(GMT+0) Azores Summer Time',
    '(GMT+5) French Southern & Antarctic Lands Time',
  ];

  beforeEach(() => {
    module('app.filters');

    inject((_$filter_) => {
      $filter = _$filter_;
    });
  });

  it('Wrong string value passed. Should return string', () => {
    expect($filter('timezoneLabel')('Hello world')).toEqual('Hello world');
  });

  it('Proper value passed. Negative offset. Should return GMT +0', () => {
    expect($filter('timezoneLabel')(timezones[0])).toEqual('GMT -11');
  });

  it('Proper value passed. Zero offset. Should return GMT +0', () => {
    expect($filter('timezoneLabel')(timezones[1])).toEqual('GMT +0');
  });

  it('Proper value passed. Positive offset. Should return GMT +5', () => {
    expect($filter('timezoneLabel')(timezones[2])).toEqual('GMT +5');
  });
});

Fixtures

Importing fixtures:

fixture.setBase('test/mocks');
  • (optional) set mocks base path
let mock = fixture.load('mock_file.json');
  • load fixture from a file

Testing Services

Service test example:

Refer to menu.srv.spec.js

Testing directives

$scope = rootScope.$new(); // also a simple empty object will do

let element = $compile('<div custom-directive')($scope);
  • Compile directive before each test
it(`Should return 'Hello world'`, () => {
  let scope = $rootScope.$new();
  scope.value = '';

  const element = $compile('<div custom-directive="value"></div>')(scope);

  expect(element.text()).toBe('');

  scope.value = 'Hello world';
  $rootScope.$digest();

  expect(element.text()).toBe('Hello world');
});
  • Run $rootScope.$digest() to apply scope changes

Testing Controllers

$scope = rootScope.$new(); // also a simple empty object will do

let CustomController = $controller('CustomController', { $scope });
  • get controller with $controller service before each test
am.controller('CustomController', function($scope, dependencyExample) => {});



const dependencyExample = { customMethod: (data) => data || [] };

let CustomController = $controller('CustomController', { $scope, dependencyExample });
  • mock dependencies if you need it

Mocking Back-end responses

$httpBackend.expectGET('/user').respond(fixture.load('user.json'));
  • expect
// will return a fixture
$httpBackend.when('/user').respond(fixture.load('user.json'));
// will return success response
$httpBackend.when('/user').respond(200);
// will return error response
$httpBackend.when('/user').respond(500);
  • when

$httpBackend service

Spies

let rabbit = {
  jump: (direction) => console.log(`Jump ${direction}!`);
}

spyOn(rabbit, 'jump');

rabbit.jump('up');

expect(rabbit.jump).toHaveBeenCalled();
expect(rabbit.jump).toHaveBeenCalledTimes(1);
expect(rabbit.jump).toHaveBeenCalledWith('up');
  • used to spy on methods and functions

Links

Unit testing AngularJS with Karma and Jasmine

By Oleksandr Hutsulyak

Unit testing AngularJS with Karma and Jasmine

  • 374