【问题标题】:Why does $httpBackend.flush() result in unexpected request?为什么 $httpBackend.flush() 会导致意外请求?
【发布时间】:2015-04-03 00:54:58
【问题描述】:

如果我添加 flush() 调用它会给我“错误:意外请求:获取模板/createAccountWithAcme.html”。为什么它告诉我有关视图模板的信息,我该如何避免这种情况?这是一个 Ionic Framework (v 1.0.0 RC2 – AngularJS) 项目。

编辑: 以前,我错误地省略了我尝试过的 $httpBackend.when 或 $httpBackend.whenGET 调用。更新代码时同样的错误:

编辑 2: 更多细节:这是一个使用 ui-router 的 Ionic 框架项目(v1.0.0 RC2)。当我尝试删除所有其他测试时,我仍然收到错误,但注意到它抱怨的模板是 UI 路由器配置中定义的最后一个模板(在 Ionic 中,路由器是 $stateProvider)。如果我在状态定义的末尾添加了一个虚拟状态,那么它就会成为测试抱怨的那个状态。所以我决定路由器必须尝试加载我的测试没有预料到的模板。我已经发布了一个修复程序。

describe('foo', function() {
  var $http, $httpBackend;
  $http = void 0;
  $httpBackend = void 0;
  $http = null;
  $httpBackend = null;
  beforeEach(module('acme'));
  beforeEach(inject(function($injector) {
    $http = $injector.get('$http');
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGET('http://www.google.com').respond({});
  }));
  it('should have parsed genres', function() {
    console.log('foo');
    $http({
      method: 'GET',
      url: 'http://www.google.com'
    }).then(function(response) {
      console.log('success: ', response);
    }, function(error) {
      console.log(error);
    });
    $httpBackend.flush();
  });
});

【问题讨论】:

  • 这是唯一运行的测试吗? acme 模块是否还有一个正在执行的运行块?
  • @Chandermani 它不是唯一运行的测试,但它是唯一失败的测试。如果我将刷新调用移到另一个测试中,它也会在那里失败。到目前为止,这是我唯一想要冲洗的地方。在我的应用程序中,acme 模块确实有一个运行块,是的,尽管我是 karma/jasmine 的新手,并且不知道在我的测试运行时该运行块是否被执行。我不这么认为,但我在假设。
  • 可能有一些路由测试正在获取模板,或者一些指令测试加载了指令模板。看你上面模板的参考代码,看看有没有对应的测试。

标签: angularjs ionic-framework karma-jasmine


【解决方案1】:

我最终将所有 html 模板列入白名单:

beforeEach ...

//this line solves it
$httpBackend.whenGET(/templates/.*/).respond(200, '');

$httpBackend.whenGET('http://www.google.com').respond({});

...

【讨论】:

  • whenGET(/templates/.*/) 似乎是语法错误。有机会就去看看?
  • @scniro 迟到了,但应该是whenGET(/templates\/.*/) - 转义正则表达式特殊符号
【解决方案2】:

在对包含其他指令的指令进行单元测试时,我看到了与 HTML 的意外获取请求类似的问题。

我/我们采用的一般解决方案是添加一些构建步骤,将项目的所有 HTML 模板“编译”(某种程度)到单个 JS 文件中,然后将该 JS 文件包含在 karma 中包含的 javascript 列表中.conf.js。现在,当指令加载并向模板缓存请求模板时,模板已经加载(因为您的 JS 是通过 karma.conf.js 包含的),然后不会出现意外的 GET 请求!

请注意,作为构建过程的一部分,这通常是一件好事,这样您的客户端浏览器就不会为 HTML 模板发出 N 个额外的 HTTP 请求。

如果您在基于 node.js 的项目中,您可以使用ng-htmljs 将所有模板转换为 js。他们的文档也更好地解释了这个问题:https://www.npmjs.com/package/ng-html2js。这也方便地由 grunt - https://www.npmjs.com/package/grunt-html2js 和 gulp - https://www.npmjs.com/package/gulp-ng-html2js 包装。

node.js grunt 解决方案更详细:

GruntFile.coffee:

grunt.initConfig
  html2js:
    test:
      src: ['all/my/html_templates/**/*.html']
      dest: 'app/.tmp/templates.js'
    options:
      base : 'app/'
      module: 'myAppTemplates'
      singleModule: true
      htmlmin:
        collapseWhitespace: false
        collapseBooleanAttributes: true
        removeCommentsFromCDATA: true
        removeOptionalTags: true

grunt.registerTask 'test', [
  ...
  'html2js:test'
  'karma:unit'
  ...
]

在 Karma.conf.js 中:

files: [
  ...
  'app/.tmp/templates.js'
],

别忘了在你的测试中包含你的模板模块:

beforeEach module 'myAppTemplates'
#or if you are using browserify:
beforeEach window.angular.mock.module 'myAppTemplates'

【讨论】:

    【解决方案3】:

    你要做的是在你的beforeEach子句中模拟你的请求:

     beforeEach(inject(function($injector) {
        $http = $injector.get('$http');
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.whenGet('http://www.google.com')
        .respond('Some return');
      }));
    

    当你执行.flush()时,get方法的promise就会解决

    【讨论】:

    • 谢谢,不知何故我不小心把我的 .when('GET', 'google.com') 丢了,我也试过 whenGET。我已经用正确的代码编辑了我的问题,但仍然出现同样的错误。
    猜你喜欢
    • 2013-05-19
    • 2011-02-16
    • 2011-07-31
    • 1970-01-01
    • 2019-06-30
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多