Unit test Angular, which refers to an external element

I have a custom directive that uses an attribute to specify another control that it modifies.

Directive definition object:

{ restrict: 'E', templateUrl: 'myTemplate.html', scope: { targetId: '@' }, controller: MyController, controllerAs: 'vm', bindToController: true } 

The function on the directive controller changes the contents of the target element (input field):

 function onSelection (value) { var $element = $('#' + vm.targetId); $element.val('calculated stuff'); $element.trigger('input'); } 

Unit tests (Jasmine / Karma / PhantomJS) are currently adding an element to the page. It works, but it sounds like the smell of code.

 beforeEach(inject(function($rootScope, $compile) { var elementHtml = '<my-directive target-id="bar"></my-directive>' + '<input type="text" id="bar">'; scope = $rootScope.$new(); angularElement = angular.element(elementHtml); angularElement.appendTo(document.body); // HELP ME KILL THIS! element = $compile(angularElement)(scope); scope.$digest(); })); afterEach(function () { angularElement.remove(); // HELP ME KILL THIS! }); 

I tried to rewrite the controller function to avoid jQuery; It did not help.

How can I revise a directive or tests to exclude appendTo / remove?

+6
source share
2 answers

It is best to transfer the directive to an attribute instead of an element. This eliminates the need for the target-id attribute, and you do not need to search for the target element.

See http://jsfiddle.net/morloch/621rp33L/

Directive

 angular.module('testApp', []) .directive('myDirective', function() { var targetElement; function MyController() { var vm = this; vm.onSelection = function() { targetElement.val('calculated stuff'); targetElement.trigger('input'); } } return { template: '<div></div>', restrict: 'A', scope: { targetId: '@' }, link: function postLink(scope, element, attrs) { targetElement = element; }, controller: MyController, controllerAs: 'vm', bindToController: true }; }); 

Test

 describe('Directive: myDirective', function() { // load the directive module beforeEach(module('testApp')); var element, controller, scope; beforeEach(inject(function($rootScope, $compile) { scope = $rootScope.$new(); element = angular.element('<input my-directive type="text" id="bar">'); $compile(element)(scope); scope.$digest(); controller = element.controller('myDirective'); })); it('should have an empty val', inject(function() { expect(element.val()).toBe(''); })); it('should have a calculated val after select', inject(function() { controller.onSelection(); expect(element.val()).toBe('calculated stuff'); })); }); 
+2
source

Here's another suggestion that supports your logic in much the same way: use the second directive to make the target element available on the controller, which can then be passed to the main directive for processing: http://jsfiddle.net/morloch/p8r2Lz1L/

getElement

  .directive('getElement', function() { return { restrict: 'A', scope: { getElement: '=' }, link: function postLink(scope, element, attrs) { scope.getElement = element; } }; }) 

myDirective

  .directive('myDirective', function() { function MyController() { var vm = this; vm.onSelection = function() { vm.targetElement.val('calculated stuff'); vm.targetElement.trigger('input'); } } return { template: '<div></div>', restrict: 'E', scope: { targetElement: '=' }, controller: MyController, controllerAs: 'vm', bindToController: true }; }) 

Test

 describe('Directive: myDirective', function() { // load the directive module beforeEach(module('testApp')); var element, controller, scope; beforeEach(inject(function($rootScope, $compile) { scope = $rootScope.$new(); element = angular.element('<input get-element="elementBar" type="text" id="bar"><my-directive target-element="elementBar"></my-directive>'); $compile(element)(scope); scope.$digest(); controller = $(element[1]).controller('myDirective'); })); it('should have an empty val', inject(function() { expect($(element[0]).val()).toBe(''); })); it('should have a calculated val after select', inject(function() { controller.onSelection(); expect($(element[0]).val()).toBe('calculated stuff'); })); }); 
+1
source

All Articles