Search code examples
angularjsjasminephantomjskarma-jasmineangular-directive

Unit test failing when directive is an Attribute


I have a directive which is declared as an Attribute:

app.directive('myDirective', function() {
    return {
        restrict: 'A',
        replace: true,
        transclude: true,
        scope: {
            data: "="
        },
        template:
            '<p class="my-paragrapgh">' +
                '<label>Hello</label>' +
            '</p>'
    }
});

I have a unit test, which is failing:

describe('myDirective test', function () {
var scope, compile, element;

beforeEach(module('myModule'));

beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();

    element = angular.element("<div my-directive></div>");
    $compile(element);
    scope.$digest();
}));

it('should have a my-paragrapgh class', function () {
    expect($(element).find('p')[0]).toHaveClass('my-paragrapgh');
});

});

However, if i convert my diretive to an Element, and remove replace and transclude:

app.directive('myDirective', function() {
    return {
        restrict: 'E',
        //replace: true,
        //transclude: true,
        scope: {
            data: "="
        },
        template:
            '<p class="my-paragrapgh">' +
                '<label>Hello</label>' +
            '</p>'
    }
});

My unit test passes:

describe('myDirective test', function () {
var scope, compile, element;

beforeEach(module('myModule'));

beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();

    element = angular.element("<my-directive></my-directive>");
    $compile(element);
    scope.$digest();
}));

it('should have a my-paragrapgh class', function () {
    expect($(element).find('p')[0]).toHaveClass('my-paragrapgh');
});

});

How can i successfully test a directive declared as an Attribute? I'm using Karma, Jasmine and PhantomJS


Solution

  • You will need to have an ng-transclude somewhere in your template when you have the transclude: true so that angular will know where to inject your HTML. Try:

    app.directive('myDirective', function() {
        return {
            restrict: 'A',
            replace: true,
            transclude: true,
    
            scope: {
                data: "="
            },
    
            template:
                '<div ng-transclude><p class="my-paragrapgh">' +
                    '<label>Hello</label>' +
                '</p></div>'
        }
    });
    

    Update

    Looks like it's the replace option that could be causing the issue.

    app.directive('myDirective', function() {
        return {
            restrict: 'A',
    
            scope: {
                data: "="
            },
    
            template:
                '<p class="my-paragrapgh">' +
                    '<label>Hello</label>' +
                '</p>'
        }
    });
    

    With replace: true you're inner HTML is:

    Fails

    <label>Hello</label>
    

    With replace undefined you have

    Pass

    <p class="my-paragrapgh"><label>Hello</label></p>