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.
Testing Directives. Directives are the most important and most complex components in AngularJS. Testing directives is tricky, as they are not called like a function. In applications, the directives are declaratively applied on the HTML template. Their actions are executed when the template is compiled and a user interacts with the directive.
Using Controllers In Directives In AngularJS. In AngularJS, you have your Views, which present data to the user; you have your Controllers, which manage the $scope (ie. view model) and expose behavior to the View; and, you have your Directives, which link user interactions to $scope behaviors.
AngularJS Testing Tips: Testing Directives. Unit tests are an essential part of software development as they help you in releasing less buggy code. Testing is one of the several things that one has to do to improve code quality. AngularJS is created with testing in mind and any code written on top of the framework can be tested easily.
When a Directive requires a Controller, it is only requiring a "directive controller". The directive doesn't have any access to the ngController-based controllers. The only thing that a directive and an ngController has is that they share (or at least share by default) the same $scope reference.
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();
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With