【问题标题】:Accessing compiled template in unit tests在单元测试中访问已编译的模板
【发布时间】:2015-01-17 13:07:27
【问题描述】:

大多数 Angular 教程都在讨论使用 Protractor 的端到端测试来测试编译后的模板是否按预期输出。我想知道是否可以通过单元测试来做到这一点。

大多数讨论在单元测试中引用 HTML 代码的教程都描述了在测试中编译您自己的书面代码,例如,以确保正确访问指令:

describe('some function', function () {
  it('should do something', inject(function ($compile, $rootScope) {
    var element = $compile('<div id = "foo" ng-hide = "somecondition">Bar</div>')($Scope);
    $rootScope.digest();
    //Search for a given DOM element and perform some test here
  }));
});

但是假设我想测试实际模板文件中的代码。就像我想测试是否成功设置了 ng-hide 一样。我希望能够做类似的事情:

describe('some function', function () {
  it('should do something', function () {
    //Get the div with ID 'foo' in the compiled template
    var elm = $('#foo');
    expect(elm.css('display')).toEqual('none');
  });
});

当我这样做时,这不起作用。 elm 被设置为一些 HTML/Javascript 代码,但不是模板的代码,elm.css('display') 返回为未定义。

有没有办法通过 Jasmine/Angular 设置对此进行单元测试?

【问题讨论】:

    标签: angularjs unit-testing jasmine


    【解决方案1】:

    使用ng-html2js 将您的HTML 模板加载到Angular 的$templateCache 中,以便它们在您的测试中可用。

    在您的测试中检索您的特定模板:

    var template = $templateCache.get('my/template.html');
    

    将模板包装在更易于使用的 jqLit​​e/jQuery 对象中:

    var element = angular.element(template);
    

    然后您可以选择模板中的元素:

    var fooEl = element.find('#foo');
    

    对于断言,您不想测试在元素上设置了display: none,这是在测试ng-hide 的内部实现。你可以相信 Angular 团队有他们自己的测试,涵盖设置 CSS 属性。相反,您想测试您是否正确编写了模板,因此更适合测试元素上是否存在 ng-hide 属性,并且它提供了正确的范围属性以绑定到:

    expect(fooEl.attr('ng-hide')).toBe('isFooElHidden');
    

    【讨论】:

    • 您能否提供更多有关“将您的 HTML 模板加载到 Angular 的 $templateCache”的详细信息?我将该服务注入到我的测试中,但没有加载模板,因此它们以未定义的形式返回。
    • 您需要使用上面链接的ng-html2js。这是一个 Karma 插件,可以检索 .html 文件并将它们插入到 Angular 的$templateCache 中。或者,您可以使用$templateCache.put 手动执行此操作,但这可能会很乏味。 $templateCache API:docs.angularjs.org/api/ng/service/$templateCache
    【解决方案2】:

    除了@user2943490的正确答案:

    • 定义专用范围而不使用 $rootScope 是一种很好的做法 var scope = $rootScope.$new(); var element = $compile(template)(scope);

    • 在大多数情况下,您希望测试内部指令范围内的属性。您可以像这样在 beforeEach 方法中定义它并在所有测试中访问它: var isolatedScope = element.isolateScope(); expect(isolatedScope.property).toEqual(value);

    【讨论】:

    • 当我尝试按照您的建议访问 element.isolateScope() 时,我得到了未定义。我的指令确实定义了一个隔离范围,但此方法不返回它。 element.scope() 有效,但另一个无效。什么情况下会是未定义的?
    • 您使用什么来加载指令的模板 - template 或 templateUrl?关于使用 templateUrl 的指令的 $compile 不会触发摘要循环这一事实已经有一些讨论,因此您需要在能够访问隔离范围之前手动执行此操作。
    猜你喜欢
    • 2013-06-01
    • 2014-09-10
    • 2014-10-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多