使用外部模板测试组件(angularjs>;=1.5)

使用外部模板测试组件(angularjs>;=1.5),angularjs,unit-testing,karma-runner,Angularjs,Unit Testing,Karma Runner,我想用一个外部模板测试一个组件。但是,每当我试图在组件中找到一个元素时,我都没有得到任何结果。看起来组件是空的 我加载模板的方式是否有问题,或者我是否正确编译了组件 项目结构: libs/ app/ arc/ app.component.js app.module.js feature1/ A.component.js A.component.spec.js A.con

我想用一个外部模板测试一个组件。但是,每当我试图在组件中找到一个元素时,我都没有得到任何结果。看起来组件是空的

我加载模板的方式是否有问题,或者我是否正确编译了组件

项目结构:

libs/
app/
    arc/
        app.component.js
        app.module.js
        feature1/
            A.component.js
            A.component.spec.js
            A.controller.js
            A.html
        feature2/
            B.component.js
            B.component.spec.js
            B.controller.js
            B.html
karma.conf.js

//jshint strict: false
module.exports = function(config) {
  config.set({
    basePath: './src/app',
    frameworks: ['jasmine'],
    files: [
      '../../libs/angular/angular.js',
      '../../libs/angular-mocks/angular-mocks.js',
      '../../libs/angular-ui-router/release/angular-ui-router.js',
      '../../libs/angular-animate/angular-animate.js',
      '../../libs/angular-resource/angular-resource.js',
      '**/*.module.js',
      '**/*.spec.js',
      '**/*.html',
    ],

    preprocessors: {
      '**/*.html': ['ng-html2js'],
      '**/!(*.mock|*.spec).js': ['coverage']
    },

    ngHtml2JsPreprocessor: {
      // strip this from the file path
      ///stripPrefix: '',
      cacheIdFromPath: function(filepath) {
        let cacheId = filepath.split('/');
        return cacheId[ cacheId.length - 1 ];
      },
      // create a single module that contains templates from all the files
      moduleName: 'templates'
    },

    colors: true,

    autoWatch: true,

    browsers: ['Chrome'],

    reporters: ["spec"],

    specReporter: {
      maxLogLines: 5,             // limit number of lines logged per test 
      suppressErrorSummary: true, // do not print error summary 
      suppressFailed: false,      // do not print information about failed tests 
      suppressPassed: false,      // do not print information about passed tests 
      suppressSkipped: true,      // do not print information about skipped tests 
      showSpecTiming: false,      // print the time elapsed for each spec 
      failFast: true              // test would finish with error when a first fail occurs.  
    }

  });
};
var AComponent = {
  templateUrl: './A.html',
  controller: 'AController',
  bindings: {
  }
};

angular
  .module('app')
  .component('feature1', AComponent );
'use strict';

describe('Component: AComponent', function () {
  beforeEach(module('app'));
  beforeEach(module('templates'));

  var element;
  var component;
  var scope;
  beforeEach(inject(function($rootScope, $compile){
    scope = $rootScope.$new();
    element = angular.element('<feature1> </feature1>');
    scope.$apply(function(){
      $compile(element)(scope);
    });
  }));

  it('should contain header element', function() {
    console.log( element.find('header').length )
  });

});
A.html

<header> test </header>
A.component.spec.js

//jshint strict: false
module.exports = function(config) {
  config.set({
    basePath: './src/app',
    frameworks: ['jasmine'],
    files: [
      '../../libs/angular/angular.js',
      '../../libs/angular-mocks/angular-mocks.js',
      '../../libs/angular-ui-router/release/angular-ui-router.js',
      '../../libs/angular-animate/angular-animate.js',
      '../../libs/angular-resource/angular-resource.js',
      '**/*.module.js',
      '**/*.spec.js',
      '**/*.html',
    ],

    preprocessors: {
      '**/*.html': ['ng-html2js'],
      '**/!(*.mock|*.spec).js': ['coverage']
    },

    ngHtml2JsPreprocessor: {
      // strip this from the file path
      ///stripPrefix: '',
      cacheIdFromPath: function(filepath) {
        let cacheId = filepath.split('/');
        return cacheId[ cacheId.length - 1 ];
      },
      // create a single module that contains templates from all the files
      moduleName: 'templates'
    },

    colors: true,

    autoWatch: true,

    browsers: ['Chrome'],

    reporters: ["spec"],

    specReporter: {
      maxLogLines: 5,             // limit number of lines logged per test 
      suppressErrorSummary: true, // do not print error summary 
      suppressFailed: false,      // do not print information about failed tests 
      suppressPassed: false,      // do not print information about passed tests 
      suppressSkipped: true,      // do not print information about skipped tests 
      showSpecTiming: false,      // print the time elapsed for each spec 
      failFast: true              // test would finish with error when a first fail occurs.  
    }

  });
};
var AComponent = {
  templateUrl: './A.html',
  controller: 'AController',
  bindings: {
  }
};

angular
  .module('app')
  .component('feature1', AComponent );
'use strict';

describe('Component: AComponent', function () {
  beforeEach(module('app'));
  beforeEach(module('templates'));

  var element;
  var component;
  var scope;
  beforeEach(inject(function($rootScope, $compile){
    scope = $rootScope.$new();
    element = angular.element('<feature1> </feature1>');
    scope.$apply(function(){
      $compile(element)(scope);
    });
  }));

  it('should contain header element', function() {
    console.log( element.find('header').length )
  });

});
“严格使用”;
描述('Component:AComponent',函数(){
在每个(模块(“应用”)之前;
每个之前(模块(“模板”);
var元素;
var分量;
var范围;
beforeach(注入(函数($rootScope,$compile){
scope=$rootScope.$new();
元素=角度。元素(“”);
作用域$apply(函数(){
$compile(元素)(范围);
});
}));
它('应该包含头元素',函数(){
console.log(element.find('header')。长度)
});
});

好的,我想我可能有一个临时解决方案

问题是,通过检查
$templateCache
,我实际上可以看到所有模板都已正确加载。然而,它们并没有作为编译过程的一部分被获取。因此,为了使其工作,我必须显式地为
$compile()
方法设置模板

ngHtml2JsPreprocessor: {
    cacheIdFromPath: function(htmlPath) {
      let cacheId = htmlPath.split('/');
      return './'+cacheId[ cacheId.length - 1 ];
    },
    // create a single module that contains templates from all the files
    moduleName: 'templates'
},
这里的主要问题是,当模板名称更改时,我也必须更新规范文件

'use strict';

describe('Component: AComponent', function () {
  beforeEach(module('app'));
  beforeEach(module('templates'));

  var element;
  var scope;
  beforeEach(inject(function($rootScope, $compile, $templateCache ){
    scope = $rootScope.$new();
    let template =  $templateCache.get('A.html');
    element = angular.element( '<feature1>'+template+'</feature1>' );
    scope.$apply(function(){
      $compile(element)(scope);
    });
  }));

  it('should contain header element', function() {
   var header = angular.element(element[0].querySelector('header'));
    expect(header.length).not.toBe(0);
  });

});
“严格使用”;
描述('Component:AComponent',函数(){
在每个(模块(“应用”)之前;
每个之前(模块(“模板”);
var元素;
var范围;
beforeach(注入函数($rootScope、$compile、$templateCache){
scope=$rootScope.$new();
让template=$templateCache.get('A.html');
元素=角度元素(“”+模板+“”);
作用域$apply(函数(){
$compile(元素)(范围);
});
}));
它('应该包含头元素',函数(){
var header=angular.element(元素[0]。querySelector('header');
expect(header.length).not.toBe(0);
});
});

正如@StanislavKvitash所指出的,
模板URL必须与组件中定义的完全相同。在我的例子中,前导“/”导致在编译组件时无法解析模板

为了解决这个问题,我刚刚在
cacheIdFromPath
方法的所有结果中添加了缺少的“/”

ngHtml2JsPreprocessor: {
    cacheIdFromPath: function(htmlPath) {
      let cacheId = htmlPath.split('/');
      return './'+cacheId[ cacheId.length - 1 ];
    },
    // create a single module that contains templates from all the files
    moduleName: 'templates'
},

删除最后一个
s
以匹配打开的Tagah my bad,这只是一个输入错误。但不是真正的根本原因。我没有看到任何元素包含class
stat
so
element.find('.stat')
将找到nothing@Alexus
$templateCache
中的
templateUrl
与组件定义中的
templateUrl>相同吗?您是对的,templateUrl。似乎名称必须完全准确,因为它是在组件中定义的。必须将前导“/”添加到
cacheIdFromPath
方法的所有结果中。