如何在AngularJS中测试控制器指令

时间:2015-10-02 15:32:41

标签: javascript angularjs jasmine bdd

经过多次研究,我无法正确测试Angular指令,因为我无法访问其控制器内的函数。

这是指令代码:

angular.module('app').
    directive("accordionItem", function () {
        return{
            restrict: 'E',
            replace: true,
            templateUrl: function (elem, attr) {
                return 'partials/invoice/' + attr.temp + '.html';
            },
            scope: {
                invoice: '=',
                temp: '@'
            },
            controller: function ($scope, listSelectionService, $state) {

            $scope.selectItem = function () {
                if ($scope.isOpen()) {
                    listSelectionService.selectedItem = -1;
                }
                else {
                    listSelectionService.selectedItem = $scope.invoice;
                }
            };
            $scope.isOpen = function () {
                return listSelectionService.selectedItem === $scope.invoice;
            };
            $scope.showFaturasSubscription = function () {
                $state.go('app.ultimasFaturasSubscription', {subscriptionId: $scope.invoice.subscriptionId});
            };
        }
    };
});

我的测试:

describe('Invoice', function() {
    var $scope = {}, controller, $httpBackend, $controller, form, element;
    beforeEach(module('app'));

    describe('Directives', function() {
        beforeEach(inject(function($compile, $rootScope, _$httpBackend_, _$controller_) {
            $httpBackend = _$httpBackend_;
            $httpBackend.expect('GET', 'data/translation/?lang=pt').respond(200, []);
            $httpBackend.when('GET', 'partials/invoice/undefined.html').respond(200, []);
            $httpBackend.when('GET', 'partials/templates/loading.html').respond(200, []);
            $httpBackend.when('GET', 'partials/invoice/invoiceContent.html').respond(200, []);
            $scope = $rootScope.$new();
            $controller = _$controller_;

            form = $compile("<accordion-item temp='invoiceContent'></accordion-item>")($scope);
            $scope.$digest();

        }));
        it('should submitButtonDisabled', inject(function($injector) {
            var listSelectionService = $injector.get("listSelectionService");
            $scope.selectItem();
            expect(listSelectionService.selectedItem).toBe(-1);
        }));
    });
});

根据我读过的许多文件,在$ digest()函数之后,我们可以访问指令的控制器。这没有发生,因为它给我以下错误:

TypeError: $scope.selectItem is not a function
at null.<anonymous> (http://localhost:8234/spec/invoice/invoiceDirectivesSpec.js:27:20)
at Object.invoke (http://localhost:8234/src/main/webapp/vendor/angular/angular.js:4452:17)
at workFn (http://localhost:8234/src/main/webapp/vendor/angular-mocks/angular-mocks.js:2420:20)
at jasmine.Block.execute (http://localhost:8234/?:1164:19)
at jasmine.Queue.next_ (http://localhost:8234/?:2196:33)
at jasmine.Queue.start (http://localhost:8234/?:2149:10)
at jasmine.Spec.execute (http://localhost:8234/?:2476:16)
at jasmine.Queue.next_ (http://localhost:8234/?:2196:33)
at jasmine.Queue.start (http://localhost:8234/?:2149:10)
at jasmine.Suite.execute (http://localhost:8234/?:2621:16)
Error: Declaration Location
    at window.inject.angular.mock.inject (http://localhost:8234/src/main/webapp/vendor/angular-mocks/angular-mocks.js:2391:25)
    at null.<anonymous> (http://localhost:8234/spec/invoice/invoiceDirectivesSpec.js:25:43)
    at jasmine.Env.describe (http://localhost:8234/?:919:23)
    at describe (http://localhost:8234/?:703:29)
    at null.<anonymous> (http://localhost:8234/spec/invoice/invoiceDirectivesSpec.js:10:5)
    at jasmine.Env.describe (http://localhost:8234/?:919:23)
    at describe (http://localhost:8234/?:703:29)
    at http://localhost:8234/spec/invoice/invoiceDirectivesSpec.js:5:1

任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:5)

我通常以与常规控制器相同的方式测试指令控制器。

在您的指令中,您已将控制器内联定义为指令的一部分。相反,像对待与视图一起使用的控制器一样定义它:

在模块上注册控制器

angular.module('app').controller('DirectiveController', function($scope) { ... });

在指令配置中引用控制器

controller: 'DirectiveController'

测试控制器

这将取代或补充实际的指令测试。在指令之外测试控制器要简单得多,您不必担心实例化指令或处理DOM元素。通常情况下,如果指令的模板足够简单,我甚至不用担心指令测试而只是测试控制器。简单的例子:

var controller, scope;

beforeEach(inject(function($rootScope, $controller) {
    scope = $rootScope.$new();
    controller = $controller('DirectiveController', {$scope: scope});
}));

describe('controller', function() {
  it('exists', function() {
    expect(controller).toBeDefined();
    expect(controller).not.toBeNull();
  });
});