After many research, I've been unable to correctly test an Angular directive, since I can't access to functions inside its controller.
Here is the directive code:
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});
};
}
};
});
And my test:
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);
}));
});
});
According to many documents I've read, after the $digest() function we can have access to the controller of the directive. This is not happening since it gives me the following error:
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
Any help would be really appreciated.
I usually test directive controllers the same way I do a regular controller.
In your directive, you have defined the controller inline, as part of the directive. Instead, define it like you would for a controller that is used with a view:
Register the controller on a module:
angular.module('app').controller('DirectiveController', function($scope) { ... });
Reference the controller in the directive configuration:
controller: 'DirectiveController'
Test the controller:
This would either replace or complement the actual directive tests. Testing the controller outside of the directive is much simpler, you don't need to worry about instantiating the directive or deal with DOM elements. Often times, if the template for the directive is simple enough, I don't even bother with directive tests and just test the controller. Simple example:
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();
});
});