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

How to test controller directives in AngularJS

本文关键字:测试 控制器 指令 AngularJS      更新时间:2023-09-26

经过多次研究,我一直无法正确测试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

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

在你的指令中,你已经定义了内联控制器,作为指令的一部分。相反,应该像定义与视图一起使用的控制器那样定义它:

在模块上注册控制器:

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();
  });
});