Проверьте директиву Angular, в которой используется jQuery

У меня возникли проблемы с написанием модульных тестов для некоторых из моих директив 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 в тест? Может быть, это ограничение Кармы? Кто-нибудь знает?

Ответ 1

Попробуйте переопределить $in beforeEach блок теста.

beforeEach(function() {
  $.fn.hide = function() {
    this.css( "display", "none" )
  };
});