javascript unit test with angular 1.x (course exercise)

Reference for angular unit testing course.

Motivation

script “compile”

Our javascript code never gets compiled, hence we are open to a lot of runtime errors..

testable code === modular code

When we write with angular, we often mistake with our module separation.

angular.module('a', [])
    .service('ServiceA', function() {
        this.getName = function() {
            return 'bob';
        }
    });
angular.module('b', [])
    .service('ServiceB', ['ServiceA', function(ServiceA) {
        this.greet = function() {
            return 'Hello ' + ServiceA.getName()
        }
    }]);
angular.module("app", ['a', 'b'])
    .controller("myCtrl", function($scope, ServiceB) {
        $scope.data = ServiceB.greet();
    });

very fast

Yes. Javascript unit testing is much faster than the alternative, slow UI testing..


jasmine

jasmine introduction

Check out jasmine docs

test a javascript function

test a javascript object

TODO: fix this test.

solution

testable code

How can we test this?

var Greeter = function() {
    function greet(name) {
        //TODO this is complex code
        console.log("Hello " + name);
    }
    this.greet = greet;
};

jasmine spies

spyOn

dependency injection?

How can we test this?

var LastNameService = function() {
    this.getLastName = function(firstName) {
        switch (firstName) {
            case "Bob":
                return "Marley";
            case "Phill":
                return "Collins";
        }
    }
};

var Greeter = function() {
    var dataService = new LastNameService();
    
    this.greet =  function greet(name) {
        return "Hello " + name + " " + dataService.getLastName(name);
    };
};

spyOn and return

TODO: fix this test.

solution

createSpyObj

TODO: fix this test.

solution


angular + jasmine

ngMock

See docs

  • angular.mock.module
  • angular.mock.inject

testing services

simple service test

TODO: fix this test.

solution

service test with spyOn

TODO: fix this test.

solution


testing services with real DI

service with inject(spyOn)

$provide

See docs

service with real DI (createSpyObj)

TODO: fix this test.

solution


testing controllers

use $controller - controllers are NOT singleton

stateless controller (controller as)

describe("MyController test suite", function() {
    var ctrl;
    beforeEach(module('MyModule'));

    beforeEach(inject(function($controller) {
        ctrl = $controller("MyController");
    }));

    it("should greet corretly", function() {
        expect(ctrl.greet()).toBe('Hello Bob');
    });


});

controller as (state on this)

TODO: fix this test.

solution

controller with $scope (state on scope)

TODO: fix this test.

solution

controller with DI

Now try to solve previous example with createSpyObj.
solution


testing directives

  • use $compile
  • test element - use jqlite selectors test

directive using scope + $watch

TODO: fix this test.

solution


testing components (angular 1.5+)

  • use $componentController to test the controller
  • use $compile to test element, like a directive

and what about testing lifecycle hooks?


Other angular patterns

test a controller using $http

use $httpBackend and don’t forget $httpBackend.flush()

TODO: write a test for the second scenario.

solution

test a controller using $timeout

don’t forget $timeout.flush()

TODO: Write a test for this controller.

solution

test a controller using events

TODO: Write a test for this controller.

solution

test a controller using promise

angular docs: “it’s important to know that the resolution of promises is tied to the digest cycle”

TODO: write a test for the second scenario.

solution


Finally

Test writing challenge