【问题标题】:Test an Angular directive that uses jQuery测试一个使用 jQuery 的 Angular 指令
【发布时间】:2014-07-25 16:37:33
【问题描述】:

我在为我的一些 Angular 指令编写单元测试时遇到问题。特别是那些在指令中使用 jQuery 的。我在下面设计了一个最小的示例来说明我的问题。

这个愚蠢的指令将点击事件绑定到元素。单击时,它会隐藏元素。 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);
    });
});

当我运行这个测试时,它失败并出现“未定义不是函数”的错误,这意味着没有加载 jQuery,而 Angular 使用了 jQuery Lite,它没有定义 hide()。

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

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

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

我觉得应该可以让 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 吗?也许这是业力的限制?有人知道吗?

【问题讨论】:

  • 你能试试expect(elm.find(":hidden").length).toBe(1);吗?
  • 它甚至没有到达那一行,因为由于我描述的事情,它在上面的行上有一个错误。
  • 哦,好的。您是如何尝试在您的应用中加载 jQuery 的?
  • 在我的业力配置文件中,我将 jQuery 作为“文件”部分的第一个文件加载,并且 jQuery 可以工作。它加载。但由于某种原因,Angular 仍然使用 jQuery Lite 作为默认的元素包装器。
  • 还没有。我想但还没有太努力去弄清楚。同时,我使用集成测试(量角器)来覆盖我的指令。

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


【解决方案1】:

尝试在测试的 beforeEach 块中覆盖 $。

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

【讨论】:

  • 我在顶部的 karma conf 文件中加载了 jquery,但我得到了 $ undefined。我们还需要做些什么来访问 jQuery 的 $ 吗?
【解决方案2】:

我能够通过在 angular 之前加载 jquery 来解决类似的问题。 此外,如果 $ 对您不利,您始终可以使用 angular.element('') 代替 $

【讨论】:

    猜你喜欢
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多