Monday, May 20, 2024
124
rated 0 times [  130] [ 6]  / answers: 1 / hits: 15227  / 11 Years ago, sat, march 30, 2013, 12:00:00

Code below executes but complains about element.popover not being invoked. I can't seem to figure out what the issue is.



Thanks for help in advance.



directive:



angular.module('directives', []).

directive('popOver', function ($http) {

return {
restrict:'C',

link: function (scope, element, attr) {
element.bind('mouseover', function (e) {
$http.get(someurl + attr.chatid + .json).success(function (data) {
element.popover({content: data.firstName + + data.lastName });
});
});
}
}
})


Jasmine test:



'user strict'

describe('directives', function() {
beforeEach(module('directives'));
describe('popOver', function() {
var $scope, compile, location, $httpBackend, elm;

beforeEach(inject(function($rootScope, $compile, _$httpBackend_) {
$scope = $rootScope.$new();
compile = $compile;
$httpBackend = _$httpBackend_;
elm = angular.element('<i class=pop-over data-placement=top data-chatid=testChatId > </i>');
compile(elm)($scope);

}));

it('should call element.popover()', function() {
$httpBackend.expectGET('someurl/testChatId.json').
respond([ {firstName: 'test', lastName: 'user'}]);

spyOn(elm, 'popover').andCallThrough();

elm.trigger('mouseover');
$httpBackend.flush();

expect(elm.popover).toHaveBeenCalled();
});
});
});


Output:



Chrome 26.0 (Mac) directives popOver should call element.popover() FAILED
Expected spy popover to have been called.
Error: Expected spy popover to have been called.

More From » unit-testing

 Answers
30

Update:



I wasn't able to solve your specific problem. Mostly because I couldn't get angular-seed going/it was taking forever, but I thought I'd make my answer more complete.



There are 2 ways to solve this problem in general:




  1. Spy on a function other than the one being triggered by some
    event/intermediary

  2. Spy on the prototype of the function before the object is created. In other words: spyOn(MyObjectNamespace.Class.prototype, 'functionToSpyOn')



Afterwards just restore and you should be fine.






I am only vaguely familiar with angular, but have experienced similar problems.



Solution 1



You can just separate out the function rather than specifying it anonymously. This helps test your functionality specifically and avoid all the angular stuff.



Solution 2



Sometimes with frameworks this isn't possible. The main problem here is that your spy is attaching itself too late and the reference is lost or gets overridden.



Test:



describe('directives', function() {
beforeEach(module('directives'));
describe('popOver', function() {
var $scope, compile, location, $httpBackend, elm;

beforeEach(inject(function($rootScope, $compile, _$httpBackend_) {
$scope = $rootScope.$new();
compile = $compile;
$httpBackend = _$httpBackend_;
elm = angular.element('<i class=pop-over data-placement=top data-chatid=testChatId > </i>');
compile(elm)($scope);

}));

it('should call element.popover()', function() {
var popoverFunction = $.fn.popover;
$httpBackend.expectGET('someurl/testChatId.json').
respond([ {firstName: 'test', lastName: 'user'}]);

spyOn($.fn, 'popover').andCallThrough();

elm.trigger('mouseover');
$httpBackend.flush();

expect($.fn.popover).toHaveBeenCalled();
//restore popover, use sinon's restore fn instead here
$.fn.popover = popoverFunction
});
});
});


You can use Sinon with Jasmine. Sinon has a spy.restore function that gets rid of the first and last line for you. In my own tests I've placed the first line and the spy creation in a beforeEach and the restore in an afterEach.


[#79229] Thursday, March 28, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
peytont

Total Points: 215
Total Questions: 110
Total Answers: 111

Location: Armenia
Member since Sat, Dec 31, 2022
1 Year ago
;