Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject a service in a directive unit test in AngularJS

I need to test a directive that does some calls to some injected services. The following piece of code is an example directive, that listens for events, and redirects the browser if enter is pressed inside a specified element.

Edit: I get the feeling I may be wading in E2E testing land?

angular.module('fooApp')   .directive('gotoOnEnter', ['$location', function ($location) {      var _linkFn = function link(scope, element, attrs) {          element.off('keypress').on('keypress', function(e) {                   if(e.keyCode === 13)                   {                        $location.path(scope.redirectUrl);                   }               });     }      return {       restrict: 'A',       link: _linkFn     };   }]); 

The problem is that I have not figured out how to inject services to spy on them in directives.

My proposed solution looks like this: It does not work, as expected, because I have not managed to inject a $locacion service successfully to spy on.

describe('Directive: gotoOnEnter', function () {   beforeEach(module('fooApp'));    var element;    it('should visit the link in scope.url when enter is pressed', inject(function ($rootScope, $compile, $location) {      element = angular.element('<input type="text" goto-on-enter>');     element = $compile(element)($rootScope);      $rootScope.redirectUrl = 'http://www.google.com';     $rootScope.$digest();      var e = jQuery.Event('keypress');     e.keyCode = 13;     element.trigger(e);      spyOn($location, 'path');      expect($location.path).toHaveBeenCalledWith('http://www.google.com');   })); 

This yields

Expected spy path to have been called with [ 'http://www.google.com' ] but it was never called. 
like image 785
Kenneth Lynne Avatar asked Apr 01 '13 22:04

Kenneth Lynne


People also ask

How do you mock a service to inject in a unit test?

var service = new MockLoginService(); beforeEachProviders(() => [ provide(TestService, { useValue: service })]); it('should load languages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { tcb . createAsync(LoginComponent). then((fixture) => { let element = fixture.

Which is used to inject a service into test function?

To test a service, you set the providers metadata property with an array of the services that you'll test or mock. content_copy let service: ValueService; beforeEach(() => { TestBed. configureTestingModule({ providers: [ValueService] }); }); Then inject it inside a test by calling TestBed.

Is AngularJS code unit testable?

AngularJS is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but if you ignore these guidelines you may end up with an untestable application.


1 Answers

To decorate, stub, provide mocks or override any given service, you may use the $provide service. $provide.value, $provide.decorator etc. Documentation here.

Then you can do stuff like this:

 var $location;   beforeEach(function() {     module('studentportalenApp', function($provide) {       $provide.decorator('$location', function($delegate) {          $delegate.path = jasmine.createSpy();          return $delegate;       });     });      inject(function(_$location_) {       $location = _$location_;     });    }); 

...

it('should visit the link in scope.redirectUrl when enter is pressed', inject(function ($rootScope, $compile, $location) {     element = angular.element('<input type="text" goto-on-enter>');     element = $compile(element)($rootScope);      $rootScope.redirectUrl = 'http://www.google.com';     $rootScope.$digest();      var e = jQuery.Event('keypress');     e.keyCode = 13;     element.trigger(e);      $rootScope.$digest();      expect($location.path).toHaveBeenCalledWith('http://www.google.com');  })); 
like image 56
Kenneth Lynne Avatar answered Sep 23 '22 01:09

Kenneth Lynne