У меня возникли проблемы с написанием модульных тестов для некоторых из моих директив Angular. В частности, те, которые используют jQuery внутри директивы. Я придумал минимальный пример ниже, который иллюстрирует мою проблему.
Эта глупая директива связывает событие click с элементом. При щелчке он скрывает элемент. Согласно Angular, элементы, переданные в директивы, будут обернуты как элементы jQuery. если jQuery доступен, он будет использовать jQuery, иначе он будет использовать Angular jQuery Lite. Действительно, если я использую эту директиву в браузере с включенным jQuery, директива работает и скроет элемент с щелчком.
angular.module('myApp').directive('clickhide', function() { return {
link: function(scope, element, attrs) {
element.bind('click', function(e) {
element.hide();
scope.$digest();
});
}
}});
Вот спецификация Karma unit test для этой директивы:
describe('clickhide', function() {
var scope, elm;
beforeEach(module('MyApp'));
beforeEach(inject(function($rootScope, $compile) {
scope = $rootScope;
elm = angular.element('<div clickhide></div>');
$compile(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);
});
});
Когда я запускаю этот тест, он терпит неудачу с ошибкой "undefined не является функцией", что означает, что jQuery не был загружен, а Angular вместо этого использовался jQuery Lite, который не определяет hide().
Я нашел два способа обойти это.
-
Не используйте jQuery. Требуется переписать мои директивы, которые я не хочу делать.
-
Явно обернуть элементы в моих директивах, чтобы сделать их элементами jQuery:
$(element).hide()
. Также требуется внести изменения в мои директивы, которые я бы предпочел не делать. Если альтернативы нет, я, безусловно, могу это сделать.
Я чувствую, что должно быть возможно получить Angular, чтобы автоматически использовать jQuery внутри директивы, когда модульное тестирование, как это происходит при использовании в веб-браузере. Я считаю, что ключевым моментом является эта строка из документации Angular:
Чтобы использовать jQuery, просто загрузите его перед запуском события DOMContentLoaded.
Неясно, когда DOMContentLoaded происходит при выполнении модульных тестов. Конфигурационный файл Karma включает jQuery в качестве первого файла до angular:
module.exports = function(config) {
config.set({
basePath: '../../',
frameworks: ['jasmine', 'ng-scenario'],
files: [
'app/bower_components/jquery/dist/jquery.min.js',
'app/bower_components/angular/angular.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-sanitize/angular-sanitize.js',
'app/bower_components/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
});
};
Нужно ли мне вставлять jQuery в тест? Может быть, это ограничение Кармы? Кто-нибудь знает?