Jasmine使用templateUrl测试AngularJS指令


70

我正在使用Jasmine编写AngularJS的指令测试,并与它们一起使用templateUrl:https : //gist.github.com/tanepiper/62bd10125e8408def5cc

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

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

从我在文档中阅读的内容来看,我认为自己做得正确,但是事实并非如此-我在这里想念的是什么?

谢谢


Answers:


70

如果您使用的是ngMockE2E或ngMock:

所有HTTP请求均使用您指定的规则在本地处理,并且不会传递到服务器。由于模板是通过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, '');
}));

2
嗯,我已经尝试过了,但是似乎在我注入之后,passThrough不能作为函数使用:TypeError:'undefined'不是函数(评估'$ httpBackend.when('GET','views / currency-select.html')。passThrough()')我还包括beforeEach(module('ngMockE2E')); 在我文件的顶部,它又回到了原始错误
Tane Piper

4
$ httpBackend Mock中没有passThrough()方法。它说对了文档。docs.angularjs.org/api/ngMock/service/$httpBackend这就是为什么您获取该功能不可用的错误。现在,如果您想在前端和单元测试中对此进行模拟,则可以使用passThrough方法-而不是在单元测试中……
Sten Muchow 2014年

3
@StenMuchow我的回答和@ tanepiper的问题是不是为ngMock模块,而ngMockE2E模块,支持passThrough()。通常,在单元测试期间不会使用它,因为单元测试不需要模板之类的任何HTTP请求,但是在它们需要且构建不编译它们的情况下,可以使用E2E后端。
乔什·大卫·米勒

@StenMuchow答案链接到文档的正确页面,但是为了避免将来造成混淆,我删除了使您感到困惑的部分。
乔什·大卫·米勒

@JoshDavidMiller可以肯定不建议使用passThrough(),但此解决方案仍未完成。实际上,必须使用ngHtml2JsPreprocessor并将示例路径的路径设置为指令中的templateUrl。
cameronroe 2014年

20

业力的方法是将模板html动态加载到$ templateCache中。你可以只使用html2js因缘预处理器,如解释在这里

这归结为在conf.js文件中的文件中添加模板' .html'以及preprocessors = {' .html':'html2js'};

和使用

beforeEach(module('..'));

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

进入您的js测试文件


3
这是一个很好的解释templateCache-way的工作方式:portlandwebworks.com/blog/…。只需注意,该博客讲述的是Karma的相当老的版本,因此今天您需要使用ng-html2js而不是html2js来将模板预处理为js。
Kaitsu

6

如果这是单元测试,则您无权访问$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预处理程序为您完成的工作。要使其正常工作,请先安装它:

$ 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'));

从这里开始应该顺畅航行。要更深入地了解此指令测试和其他指令测试场景,请查看这篇文章。


5

您也许可以$templatecache从进样器中取出,然后执行类似的操作

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

其中代替<div.....>你要放你的模板。

之后,您设置了指令,它应该可以正常工作!


6
我使用$ httpBackend做类似的事情,使用$ httpBackend.when('GET','views / currency-select.html')。respond('<select ng-options =“ currency.name表示货币中的货币” ng-model =“ selected_currency”> </ select>');-但是,它会击败DRY-我希望它加载我的模板,而不必再次在代码中重复它们。
塔恩·派珀

对于长的HTML模板来说不是很好,但是它使我摆脱了已经呆了好几个小时的地方!谢谢!
布兰特

4

如果仍然无法使用,请使用提琴手查看由htmltojs处理器动态生成的js文件的内容,并检查模板文件的路径。

应该是这样的

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

就我而言,这与导致问题的实际指令不同。

在所有地方都具有完全相同的templateURL可以使我理解。


1
文件路径不同对我造成了此错误
Nicholas Murray

4

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


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

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


2

这是示例如何测试使用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();
  })
});

0

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


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);
        }));

    });
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.