Thomas
Thomas

Reputation: 1140

Testing angularjs directive attributs with jasmine

I am relatively new to jasmine tests, and I've got some problem with it. I try to test this directive :

DIRECTIVE

myApp.LoadingsDirective = function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div class="loading"><img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" width="20" height="20" /></div>',
        link: function (scope, element, attrs) {
            scope.$watch(
                function(scope) {
                    return scope.$eval(attrs.show);
                },
                function(val) {
                    if (val){
                        $(element).show();
                    }
                    else{
                        $(element).hide();
                    }
                })
        }
    }
}
    myApp.directive('loading', myApp.LoadingsDirective);

This directive just show a loading icon until the result of a asynchronious request replace it.

I try something like this :

TEST

describe('Testing directives', function() {
    var $scope, $compile, element;

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

        inject(function($rootScope, _$compile_) {
            $scope = $rootScope.$new();
            $compile = _$compile_;
        });
    });

    it('ensures directive show the loading when show attribut is true', function() {
        // GIVEN
        var element = $compile('<div><loading show="true"> </loading></div>')($scope);
        var loadingScope = element.find('loading').scope();

        // WHEN
        loadingScope.$watch();

        // THEN
        expect(loadingScope.show).toBe('true');
    });
});

What is the best way to test this type of directive ? How to get access to attributs and test it ?

Upvotes: 0

Views: 239

Answers (1)

23tux
23tux

Reputation: 14746

I always do it this way (coffeescript, but you'll get the idea):

'use strict';

describe 'Directive: yourDirective', ->
  beforeEach module('yourApp')

  # angular specific stuff
  $rootScope = $compile = $scope = undefined
  beforeEach inject (_$rootScope_, _$compile_) ->
    $rootScope = _$rootScope_
    $scope = $rootScope.$new()
    $compile = _$compile_

  # object specific stuff
  element = createElement = undefined
  beforeEach inject () ->
    createElement = () ->
      element = angular.element("<your-directive></your-directive>")
      $compile(element)($scope)
      $scope.$digest()

  it "should have a headline", ->
    createElement()
    element.find("a").click()
    $scope.$apply()
    expect(element.find("input").val()).toEqual("foobar")
    expect($scope.inputModel).toEqual("foobar")

And this could be the directive:

<your-directive>
  <a ng-click="spanModel='foobar'">set inputModel</a>
  <input ng-model="inputModel">
</your-directive>

First, I extract the creation of your element into a function. This allows you to do some initial setup before the directive is created.

Then I perform some actions on my directive. If you want to apply this actions into your scope (remember in jasmine you are NOT inside angulars' digest circle), you have to call $scope.$apply() or $scope.$digest() (can't remember right now what the exact difference was).

In the example above, you click on the <a> element, and this has a ng-click attached. This sets the inputModel scope variable.

Not tested, but you'll get the idea

Upvotes: 1

Related Questions