admin管理员组文章数量:1424902
I am having trouble writing unit tests for some of my Angular directives. Particularly, those that use jQuery inside the directive. I have contrived an minimal example below that illustrates my issue.
This silly directive binds the click event to the element. When clicked, it hides the element. According to Angular, elements passed into directives will be wrapped as jQuery elements. if jQuery is available it will use jQuery, otherwise it will use Angular's jQuery Lite. Indeed, if I use this directive in a browser with jQuery included, the directive works and will hide the clicked element.
angular.module('myApp').directive('clickhide', function() { return {
link: function(scope, element, attrs) {
element.bind('click', function(e) {
element.hide();
scope.$digest();
});
}
}});
Here is the Karma unit test spec for this directive:
describe('clickhide', function() {
var scope, elm;
beforeEach(module('MyApp'));
beforeEach(inject(function($rootScope, $pile) {
scope = $rootScope;
elm = angular.element('<div clickhide></div>');
$pile(elm)(scope);
scope.$digest();
}));
it('should do a click', function() {
elm[0].click();
//OOPS: undefined is not a function error
expect($(elm).find(":hidden").length).toBe(1);
});
});
When I run this test, it fails with an error of "undefined is not a function" meaning that jQuery was not loaded and Angular used jQuery Lite instead, which doesn't define hide().
I have found two ways to work around this.
Don't use jQuery. Requires rewriting my directives which I don't want to do.
Explicitly wrap elements in my directives to make them jQuery elements:
$(element).hide()
. Also requires modifications to my directives, which I would prefer not to do. If there is no alternative, I can certainly do this.
I feel like it should be possible to get Angular to automatically use jQuery inside a directive when unit testing like it does when using in a web browser. I believe the key point is this line from Angular's documentation:
To use jQuery, simply load it before DOMContentLoaded event fired.
Its not clear to me when DOMContentLoaded happens when running unit tests. My Karma config file includes jQuery as the first file, before angular:
module.exports = function(config) {
config.set({
basePath: '../../',
frameworks: ['jasmine', 'ng-scenario'],
files: [
'app/bower_ponents/jquery/dist/jquery.min.js',
'app/bower_ponents/angular/angular.js',
'app/bower_ponents/angular-route/angular-route.js',
'app/bower_ponents/angular-sanitize/angular-sanitize.js',
'app/bower_ponents/angular-mocks/angular-mocks.js',
...
],
exclude: [],
reporters: ['progress'],
port: 9876,
runnerPort: 9100,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
captureTimeout: 60000,
singleRun: false
});
};
Do I need to inject jQuery into the test? Maybe this is a limitation of Karma? Anyone know?
I am having trouble writing unit tests for some of my Angular directives. Particularly, those that use jQuery inside the directive. I have contrived an minimal example below that illustrates my issue.
This silly directive binds the click event to the element. When clicked, it hides the element. According to Angular, elements passed into directives will be wrapped as jQuery elements. if jQuery is available it will use jQuery, otherwise it will use Angular's jQuery Lite. Indeed, if I use this directive in a browser with jQuery included, the directive works and will hide the clicked element.
angular.module('myApp').directive('clickhide', function() { return {
link: function(scope, element, attrs) {
element.bind('click', function(e) {
element.hide();
scope.$digest();
});
}
}});
Here is the Karma unit test spec for this directive:
describe('clickhide', function() {
var scope, elm;
beforeEach(module('MyApp'));
beforeEach(inject(function($rootScope, $pile) {
scope = $rootScope;
elm = angular.element('<div clickhide></div>');
$pile(elm)(scope);
scope.$digest();
}));
it('should do a click', function() {
elm[0].click();
//OOPS: undefined is not a function error
expect($(elm).find(":hidden").length).toBe(1);
});
});
When I run this test, it fails with an error of "undefined is not a function" meaning that jQuery was not loaded and Angular used jQuery Lite instead, which doesn't define hide().
I have found two ways to work around this.
Don't use jQuery. Requires rewriting my directives which I don't want to do.
Explicitly wrap elements in my directives to make them jQuery elements:
$(element).hide()
. Also requires modifications to my directives, which I would prefer not to do. If there is no alternative, I can certainly do this.
I feel like it should be possible to get Angular to automatically use jQuery inside a directive when unit testing like it does when using in a web browser. I believe the key point is this line from Angular's documentation:
To use jQuery, simply load it before DOMContentLoaded event fired.
Its not clear to me when DOMContentLoaded happens when running unit tests. My Karma config file includes jQuery as the first file, before angular:
module.exports = function(config) {
config.set({
basePath: '../../',
frameworks: ['jasmine', 'ng-scenario'],
files: [
'app/bower_ponents/jquery/dist/jquery.min.js',
'app/bower_ponents/angular/angular.js',
'app/bower_ponents/angular-route/angular-route.js',
'app/bower_ponents/angular-sanitize/angular-sanitize.js',
'app/bower_ponents/angular-mocks/angular-mocks.js',
...
],
exclude: [],
reporters: ['progress'],
port: 9876,
runnerPort: 9100,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
captureTimeout: 60000,
singleRun: false
});
};
Do I need to inject jQuery into the test? Maybe this is a limitation of Karma? Anyone know?
Share Improve this question edited Aug 9, 2014 at 3:10 Jake asked Jul 25, 2014 at 16:37 JakeJake 1,1851 gold badge14 silver badges26 bronze badges 13-
Could you try
expect(elm.find(":hidden").length).toBe(1);
? – glepretre Commented Jul 28, 2014 at 9:07 - It doesn't even get to that line because it has an error on the line above because of the thing I described. – Jake Commented Jul 29, 2014 at 15:12
- oh ok. How have you tried to load jQuery in your app? – glepretre Commented Jul 30, 2014 at 7:07
- In my karma config file, I load jQuery as the first file in the "files" section and jQuery works. It loads. But for some reason angular still uses jQuery Lite as the default element wrapper. – Jake Commented Jul 31, 2014 at 15:08
- 1 Not yet. I would like to but haven't tried too hard to figure it out. In the meantime, I use integration testing (Protractor) to cover my directives. – Jake Commented Oct 31, 2014 at 21:44
2 Answers
Reset to default 2Try to override $ in beforeEach block of the test.
beforeEach(function() {
$.fn.hide = function() {
this.css( "display", "none" )
};
});
I was able to resolve similar issue by loading jquery before angular. Also if $ is failing for you, You can always use angular.element('') in place of $
本文标签: javascriptTest an Angular directive that uses jQueryStack Overflow
版权声明:本文标题:javascript - Test an Angular directive that uses jQuery - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745361547a2655318.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论