【问题标题】:Jasmine tests AngularJS Directives with templateUrlJasmine 使用 templateUrl 测试 AngularJS 指令
【发布时间】:2013-01-23 12:55:37
【问题描述】:

我正在用 Jasmine 为 AngularJS 编写指令测试,并使用 templateUrl:https://gist.github.com/tanepiper/62bd10125e8408def5cc

但是,当我运行测试时,我得到了 gist 中包含的错误:

Error: Unexpected request: GET views/currency-select.html

从我在文档中阅读的内容来看,我认为我这样做是正确的,但事实并非如此 - 我在这里遗漏了什么?

谢谢

【问题讨论】:

标签: unit-testing angularjs jasmine angularjs-directive


【解决方案1】:

如果您使用的是 ngMockE2E 或 ngMock:

all HTTP 请求使用您指定的规则在本地处理,none 被传递到服务器。由于模板是通过 HTTP 请求的,因此它们也在本地处理。由于当您的应用程序尝试连接到 views/currency-select.html 时您没有指定任何操作,它会告诉您它不知道如何处理它。您可以轻松地告诉 ngMockE2E 传递您的模板请求:

$httpBackend.whenGET('views/currency-select.html').passThrough();

请记住,如果您愿意,您还可以在路由路径中使用正则表达式来传递所有模板。

文档对此进行了更详细的讨论:http://docs.angularjs.org/api/ngMockE2E.$httpBackend

否则使用这个:

您需要使用$injector 来访问新的后端。来自链接的文档:

var $httpBackend;
beforeEach(inject(function($injector) {
  $httpBackend = $injector.get('$httpBackend');
  $httpBackend.whenGET('views/currency-select.html').respond(200, '');
}));

【讨论】:

  • 嗯,我试过了,但似乎在我注入后,passThrough 不能作为函数使用:TypeError: 'undefined' is not a function (evalating '$httpBackend.when ('GET', 'views/currency-select.html').passThrough()') 我还包括 beforeEach(module('ngMockE2E'));在我的文件顶部,它会回到原来的错误
  • $httpBackend Mock 中没有 passThrough() 方法。它在文档中说得对。 docs.angularjs.org/api/ngMock/service/$httpBackend 这就是为什么你得到函数不可用错误的原因。现在,如果你想在前端和单元测试中模拟它,你可以使用 passThrough 方法——只是在单元测试中没有......
  • @StenMuchow 我的回答和@tanepiper 的问题不是针对ngMock 模块,而是针对ngMockE2E 模块,它确实 支持passThrough()。通常,在单元测试期间不会使用它,因为单元测试不需要像模板这样的任何 HTTP 请求,但如果它们需要并且构建不编译它们,则可以使用 E2E 后端。
  • @StenMuchow 答案链接到文档的正确页面,但为了避免将来造成混淆,我删除了让您感到困惑的部分。
  • @JoshDavidMiller 很确定 passThrough() 已被弃用,但这个解决方案仍然不完整。必须实际使用 ngHtml2JsPreprocessor 并将路径设置为示例路径作为指令中的 templateUrl。
【解决方案2】:

您也许可以从注射器中获取$templatecache,然后执行类似的操作

$templateCache.put("views/currency-select.html","<div.....>");

代替&lt;div.....&gt;,您将放置您的模板。

然后你设置你的指令,它应该可以正常工作!

【讨论】:

  • 我使用 $httpBackend 做了类似的事情 $httpBackend.when('GET', 'views/currency-select.html').respond(''); - 但是它有点打败 DRY - 我希望它加载我的模板,而不必再次在代码中重复它们。
  • 不适合长 HTML 模板,但它让我超越了我被困了几个小时的地方!谢谢!
【解决方案3】:

Karma 方式是将模板 html 动态加载到 $templateCache 中。您可以只使用 html2js 业力预处理器,如 here 解释的那样

这归结为将模板“.html”添加到 conf.js 文件中的文件中 以及 预处理器 = { '.html': 'html2js' };

并使用

beforeEach(module('..'));

beforeEach(module('...html', '...html'));

进入你的 js 测试文件

【讨论】:

  • 这里有一个很好的解释 templateCache-way 是如何工作的:portlandwebworks.com/blog/…。请注意,该博客谈到了一个相当老的 Karma 版本,所以今天你需要使用 ng-html2js 而不是 html2js 来将模板预处理为 js。
【解决方案4】:

如果还是不行,用fiddler查看htmltojs处理器动态生成的js文件内容,查看模板文件路径。

应该是这样的

angular.module('app/templates/yourtemplate.html', []).run(function($templateCache) {
  $templateCache.put('app/templates/yourtemplate.html', 

在我的情况下,它与导致问题的实际指令中的不同。

在所有地方都有完全相同的 templateURL 让我通过了。

【讨论】:

  • 文件路径不同导致我出现此错误
【解决方案5】:

如果您将jasmine-maven-plugin 与RequireJS 一起使用,您可以使用text plugin 将模板内容加载到变量中,然后将其放入模板缓存中。


define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
    "use strict";

    describe('Directive TestSuite', function () {

        beforeEach(inject(function( $templateCache) {
            $templateCache.put("path/to/template.html", directiveTemplate);
        }));

    });
});

【讨论】:

    【解决方案6】:

    根据要求,将评论转换为答案。


    对于想要在 Yeoman 应用中使用 @Lior 答案的人:

    有时在 karma 配置中引用模板的方式,因此 - ng-html2js 生成的模块名称与指令定义中指定为 templateUrls 的值不匹配。
    您需要调整生成的模块名称以匹配 templateUrls。
    这些可能会有所帮助:

    【讨论】:

      【解决方案7】:

      这是如何测试使用 partial 作为 templateUrl 的指令的示例

      describe('with directive', function(){
        var scope,
          compile,
          element;
      
        beforeEach(module('myApp'));//myApp module
      
        beforeEach(inject(function($rootScope, $compile, $templateCache){
         scope = $rootScope.$new();
         compile = $compile;
      
         $templateCache.put('view/url.html',
           '<ul><li>{{ foo }}</li>' +
           '<li>{{ bar }}</li>' +
           '<li>{{ baz }}</li>' +
           '</ul>');
         scope.template = {
           url: 'view/url.html'
          };
      
         scope.foo = 'foo';
         scope.bar = 'bar';
         scope.baz = 'baz';
         scope.$digest();
      
         element = compile(angular.element(
          '<section>' +
            '<div ng-include="template.url" with="{foo : foo, bar : bar, baz : baz}"></div>' +
            '<div ng-include="template.url" with=""></div>' +
          '</section>'
           ))(scope);
         scope.$digest();
      
       }));
      
        it('should copy scope parameters to ngInclude partial', function(){
          var isolateScope = element.find('div').eq(0).scope();
          expect(isolateScope.foo).toBeDefined();
          expect(isolateScope.bar).toBeDefined();
          expect(isolateScope.baz).toBeDefined();
        })
      });
      

      【讨论】:

        【解决方案8】:

        如果这是一个单元测试,您将无法访问$httpBackend.passthrough()。这仅在 ngMock2E2 中可用,用于端到端测试。我同意涉及ng-html2js(以前称为html2js)的答案,但我想在这里扩展它们以提供完整的解决方案。

        为了呈现你的指令,Angular 使用$http.get()templateUrl 获取你的模板。因为这是单元测试并且加载了angular-mocks,所以angular-mocks 拦截了对$http.get() 的调用并给你Unexpected request: GET 错误。您可以尝试找到绕过它的方法,但使用 Angular 的 $templateCache 预加载模板要简单得多。这样,$http.get() 甚至不会成为问题。

        这就是ng-html2js preprocessor 为您做的事情。要让它工作,首先安装它:

        $ npm install karma-ng-html2js-preprocessor --save-dev
        

        然后通过在karma.conf.js 中添加/更新以下字段来配置它

        {
            files: [
              //
              // all your other files
              //
        
              //your htmp templates, assuming they're all under the templates dir
              'templates/**/*.html'
            ],
        
            preprocessors: {
                //
                // your other preprocessors
                //
        
                //
                // tell karma to use the ng-html2js preprocessor
                "templates/**/*.html": "ng-html2js"
            },
        
            ngHtml2JsPreprocessor: {
                //
                // Make up a module name to contain your templates.
                // We will use this name in the jasmine test code.
                // For advanced configs, see https://github.com/karma-runner/karma-ng-html2js-preprocessor
                moduleName: 'test-templates',
            }
        }
        

        最后,在您的测试代码中,使用您刚刚创建的test-templates 模块。只需将test-templates 添加到您通常在beforeEach 中进行的模块调用中,如下所示:

        beforeEach(module('myapp', 'test-templates'));
        

        从这里开始应该一帆风顺。要更深入地了解这个和其他指令测试场景,请查看this post

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-25
          • 2016-01-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-03
          • 2014-07-01
          相关资源
          最近更新 更多