测试使用jQuery的Angular指令

时间:2014-07-25 16:37:33

标签: javascript jquery angularjs unit-testing karma-runner

我在为一些Angular指令编写单元测试时遇到了麻烦。特别是那些在指令中使用jQuery的人。我已经设计了一个简单的例子来说明我的问题。

这个愚蠢的指令将click事件绑定到元素。单击时,它会隐藏元素。 According to 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单元测试规范:

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 is not a function”的错误,意味着没有加载jQuery而Angular使用了jQuery Lite,而没有定义hide()。

我找到了解决这个问题的两种方法。

  1. 不要使用jQuery。需要重写我不想做的指令。

  2. 在我的指令中明确地包装元素以使它们成为jQuery元素:$(element).hide()。还需要修改我的指令,我不想这样做。如果没有其他选择,我当然可以这样做。

  3. 我觉得应该可以让Angular在指令中自动使用jQuery,就像在Web浏览器中使用单元测试一样。我认为关键点在于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注入测试?也许这是Karma的限制?有人知道吗?

2 个答案:

答案 0 :(得分:2)

尝试在每个测试块之前覆盖$ in。

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

答案 1 :(得分:0)

我能够通过在angular之前加载jquery来解决类似的问题。 同样,如果$对您而言失败,则始终可以使用angular.element('')代替$