Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test an angular directive

Unit testing an angular directive is not very hard, but I found out that there are different ways to do it.

For the purpose of this post, lets assume the following directive

angular.module('myApp')
    .directive('barFoo', function () {
        return {
            restrict: 'E',
            scope: true,
            template: '<p ng-click="toggle()"><span ng-hide="active">Bar Foo</span></p>',
            controller: function ($element, $scope) {
                this.toggle() {
                    this.active = !this.active;
                }
            }
        };
    });

Now I can think of two ways to unit test this

Method 1:

describe('Directive: barFoo', function () {
    ...
    beforeEach(inject(function($rootScope, barFooDirective) {
        element = angular.element('<bar-foo></bar-foo>');
        scope = $rootScope.$new();
        controller = new barFooDirective[0].controller(element, scope);
    }));

    it('should be visible when toggled', function () {
        controller.toggle();
        expect(controller.active).toBeTruthy();
    });
});

Method 2:

beforeEach(inject(function ($compile, $rootScope) {
    element = angular.element('<bar-foo></bar-foo>');
    scope = $rootScope.$new();
    $compile(element)(scope);
    scope.$digest();
}));

it ('should be visible when toggled', function () {
    element.click();
    expect(element.find('span')).not.toHaveClass('ng-hide');
});

So, I'm curious what the pro's and cons are of both methods and which one is most robust ?

like image 456
Jeanluca Scaljeri Avatar asked Nov 17 '15 13:11

Jeanluca Scaljeri


1 Answers

Here is how you test your AngularJS directive :

describe('Directive: barFoo', function () {
  var createElement, element, parentScope, directiveScope;
  
  beforeEach(module('myApp'));

  beforeEach(inject(function($injector) {
    var $compile = $injector.get('$compile');
    var $rootScope = $injector.get('$rootScope'),

    parentScope = $rootScope.$new();
    parentScope.paramXyz = ...  <-- prepare whatever is expected from parent scope

    createElement = function () {
      element = $compile('<bar-foo></bar-foo>')(parentScope);
      directiveScope = element.isolateScope();
      parentScope.$digest();
      $httpBackend.flush(); <-- if needed
    };
  }));


  it('should do XYZ', function() {
    parentScope.xyz = ...    <-- optionnal : adjust scope according to your test
    createElement();

    expect(...) <-- whatever, examples :

    var submitButton = element.find('button[type="submit"]');
    expect( submitButton ).to.have.value('Validate');
    expect( submitButton ).to.be.disabled;
    submitButton.click();
  });
like image 150
Offirmo Avatar answered Sep 27 '22 17:09

Offirmo