javascript 如何测试 angularjs 指令以监视函数调用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15720072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I test angularjs directive to spy on the function call?
提问by anazimok
Code below executes but complains about element.popover not being invoked. I can't seem to figure out what the issue is.
下面的代码执行但抱怨 element.popover 没有被调用。我似乎无法弄清楚问题是什么。
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.
采纳答案by Parris
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.
我无法解决您的具体问题。主要是因为我无法让 angular-seed 运行/它需要永远,但我想我会让我的答案更完整。
There are 2 ways to solve this problem in general:
一般有两种方法可以解决这个问题:
- Spy on a function other than the one being triggered by some event/intermediary
- Spy on the prototype of the function before the object is created. In other words:
spyOn(MyObjectNamespace.Class.prototype, 'functionToSpyOn')
- 监视除由某些事件/中介触发的功能以外的功能
- 在创建对象之前监视函数的原型。换句话说:
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.
我对angular只是模糊的熟悉,但也遇到过类似的问题。
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
解决方案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.
有时使用框架这是不可能的。这里的主要问题是您的 spy 附加自身太晚,并且参考丢失或被覆盖。
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.
您可以将诗乃与茉莉花一起使用。Sinon 有一个 spy.restore 功能,可以为您删除第一行和最后一行。在我自己的测试中,我将第一行和间谍创建放在 beforeEach 中,将恢复放在 afterEach 中。
回答by hatim
I got it to work.
jquery and jquery popover js files need to be loaded before angular.js during the test. This order should be specified in the testacular.conf.js file. Also, the url for http was missing ‘/'. Here is the code that is working for me:
我让它工作。
测试时需要在angular.js之前加载jquery和jquery popover js文件。这个顺序应该在 testacular.conf.js 文件中指定。此外,http 的 url 缺少“/”。这是对我有用的代码:
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
});
});
});
}
}
})
'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();
spyOn($.fn, 'popover').andCallThrough();
elm.trigger('mouseover');
$httpBackend.flush();
//expect(elm.popover).toHaveBeenCalled();
expect($.fn.popover).toHaveBeenCalled();
});
});
});