Test Driven Development for AngularJS

Andrey Kucherenko @EPAM Systems

TDD steps

  • Navigation map

  • Test first

  • Assert first

  • Fail first

Istanbul

Show me the source!

chai.should();

beforeEach(function() {
    window.env = sinon.sandbox.create();
});

afterEach(function() {
    window.env.restore();
});

test_config.js

describe('app::service MyService', function() {
    var sut, $q;

    beforeEach(module('app'));

    beforeEach(inject(function(MyService, _$q_) {
        sut = MyService;
        $q = _$q_;
    }));

    context("some context", function () {
        it('should be here', function () {
            sut.context.should.have.been.called;
        });
    });
});

*Service.spec.js

describe('app: routes: MyRouter', function() {
    var $state;

    beforeEach(function() {
        module('app');

        inject(function(_$state_) {
            $state = _$state_;
        });
    });

    describe('my menu', function() {

        it('should have url', function() {
            $state.get('my.menu').url.should.equal('/my_menu');
        });

        it('should run my application', function() {
            $state.get('my.menu').views['menu@my'].controller.should.equal('MyController');
        });

    });
});

*Router.spec.js


describe('directive: myDirective', function () {

    var $compile;
    var scope, element;
  
    beforeEach(function () {
        module('app');
        inject(function (_$rootScope_, _$compile_) {
            scope = _$rootScope_.$new();
            $compile = _$compile_;
        });
        element = $compile('<div my-directive></div>')(scope);
    });

    it('should blur if element was selected', function () {
        element.triggerHandler(focusInEvent);
        inputBlur.should.have.been.called;
    });
  });

*Directive.spec.js

describe('directive: mySecondDirective', function () {
    var sut;
    beforeEach(function () {

        module('app', function ($provide) {
            $provide.constant('info', info);
        });

        inject(function (mySecondDirective) {
            sut = mySecondDirective[0];
        });
    });

    describe('scope', function () {
        var scope;
        beforeEach(function () {
            scope = {};
            sut.link(scope);
        });

        it('should has info on scope', function () {
            scope.info.should.equal(info);
        });
    });

    it('should be used as element', function () {
        sut.restrict.should.equal('E');
    });
});

*Directive.spec.js

it('has matching keys for both french and english', 
    inject(function (resourcesEN_CA, resourcesFR_CA) {
        resourcesEN_CA.should.have.equalKeys(resourcesFR_CA);
    }
));

i18n

Performance

INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket OzY3MGHbstNJMXAeBar2 with id 44096908
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................





................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
.................................................................
PhantomJS 2.1.1 (Linux 0.0.0): Executed 3745 of 3746 (skipped 1) SUCCESS (1 min 20.57 secs / 0.735 secs)
beforeEach(module('app'));


////

angular
    .module('app')
    .config(routeConfig);

/*@ngInject*/
function routeConfig($stateProvider) {
    $stateProvider.state('login', {
        url: '/login',
        abstract: true,
        templateUrl: 'login/login/login_base.html',
        onEnter: onEnterLoginState
    });

=======================================
Started tests for module "routes"
=======================================

INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket 8oCckDjS8-mA0zJkDzgx with id 20266012
................................................................................
..........................................
PhantomJS 2.1.1 (Linux 0.0.0): Executed 122 of 122 SUCCESS (2.687 secs / 0.043 secs)

=======================================
Started tests for module "no-routes"
=======================================

INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket vW_JeAVUD-YKRYnWD1cx with id 76928838
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................


................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
.......................
PhantomJS 2.1.1 (Linux 0.0.0): Executed 3623 of 3624 (skipped 1) SUCCESS (44.292 secs / 0.685 secs)

istanbul-combine

+

 - Combine JS files (remap-istanbul)

 - Avoid memory leacks

 - Less DOM manipulation (no $compile)

 - Don't use DI from Angular JS (webpack import or browserify)

2

"karma-phantomjs-launcher": "^1.0.0"

Thank you!

Questions?