0

期望:当测试一个template或输出的directive/应该翻译的翻译以显示实际文本component时。<h1>{{home.title | translate}}</h1><h1>Home Page</h1>

现在经过大量挖掘,我已经能够通过手动将我需要的翻译放入测试中来使其工作。

示例:当前测试在测试中使用手动翻译设置,这里的关键是$translateProvider.translations.

(function() {
'use strict';

describe('home component', function() {
  var rootscope, compile, directiveElement;
  beforeEach(module('Templates'));
  beforeEach(module('myApp'));

  beforeEach(module('tmh.dynamicLocale'), function () {
    tmhDynamicLocaleProvider.localeLocationPattern('base/angular/i18n/angular-locale_{{locale}}.js');
  });

  beforeEach(module('pascalprecht.translate', function ($translateProvider) { 
    $translateProvider.translations('en', {
      "home":{
         "title": "Home page"
      }
    });
  }));

  beforeEach(inject(function(_$rootScope_, _$compile_) {
    rootscope = _$rootScope_.$new();
    compile = _$compile_;
  }));

  function getCompiledElement(){
    var element = angular.element('<home-component></home-component');
    var compiledElement = compile(element)(rootscope);
    rootscope.$digest();
    return compiledElement;
  }

  describe('home', function () {
    it('should have template defined', function () {
     directiveElement = getCompiledElement();
     console.log('my component compiled', directiveElement);
    });
  });
 });
 })();

生成的输出是正确的:

主页

现在,上面编译了我的组件并显示正确翻译的文本,而不是看到花括号和键。现在在一个实际的应用程序中,必须手动获取所需的翻译并将其放入并不是很好,而且翻译可能会发生变化,您可能会忘记更新测试。

我希望我的测试使用实际的静态json翻译文件

resources
  | locale-en_US.json

我尝试使用下面的代码,但是由于它是异步的,它不会在测试进行时加载。我需要一种方法来等到文件加载完毕,或者以不同的方式将文件加载到$translateProvider.

$translateProvider.useStaticFilesLoader({
  prefix: 'app/resources/locale-', // path to translations files
  suffix: '.json'
});   

我还尝试通过karma.conf.js如下所示加载语言 json 文件。

Files[
   ...
   { pattern: 'app/resources/angular-i18n/*.js', included: true, served: true },
   {pattern: 'app/resources/*.json', included: true, served: true},
 ]

我知道必须有一种方法可以工作,但是我还没有找到解决方案。有人说他们的解决方案有效,但是我尝试使用不同的插件,但似乎仍然无法正常工作。

更新:自定义加载器

我正在阅读为$translateProvider. 我不确定如何构建它以处理我想要的方式,以便它可以用于正确测试,但如果其他人正在研究这个,那么这可能是一个值得关注的地方。

$provide.factory('customLoader', function ($q) {
    return function () {
      var deferred = $q.defer();
      deferred.resolve({});
      return deferred.promise;
    };
  });

  $translateProvider.useLoader('customLoader');
4

2 回答 2

0

好吧,在深入挖掘之后,我想我想出了一个不太老套且相当干净的解决方案。首先我安装并按照这个插件的说明Karma-fixture https://www.npmjs.com/package/karma-fixture

设置好夹具后,我调用创建的全局变量karma-fixture并在我的测试中使用它来获取我想要的 json 文件,并将其干净地加载到$translateProvider.translations如下所示的文件中。

注意:模板和夹具以及文件很重要:

beforeEach(module('pascalprecht.translate', function ($translateProvider) {

   $translateProvider.translations('en', 
     fixture.load('app/resources/locale-en_US.json')
   );

   $translateProvider.preferredLanguage('en');
}));

一个 Jasmine 单元测试的完整工作示例,它编译了一个带有以下翻译的组件。

Karma.conf.js:文件

module.exports = function(config) {
  'use strict';

   config.set({
     autoWatch: true,
     basePath: '../',

     frameworks: ['jasmine', 'fixture'],

     files: [
       // bower:js
       ... <-Bower files Here ->
       // endbower
       {pattern: 'app/resources/angular-i18n/*.js', included: true, served: true },
       {pattern: 'app/resources/*.json', included: true, served: true},
       'app/**/*.app.js',     // First load main module
       'app/**/*.module.js',  // Then Load all modules
       'app/**/*.tpl.html',   // Then Load all html pages
       'app/**/!(*.spec).js', // Then load all javascript files that are not tests
       'app/**/*.spec.js'     // Finally load all tests
     ],

     exclude: [
       'app/css/**/*.js',
       'app/js/**/*.js',
       'app/styles/vendor/**/*.js'
     ],

     port: 8080,

     browsers: ['PhantomJS'],

     plugins: [
       'karma-phantomjs-launcher',
       'karma-chrome-launcher', 
       'karma-jasmine',
       'karma-coverage',
       'karma-ng-html2js-preprocessor',
       'karma-json-fixtures-preprocessor',
       'karma-fixture'
     ],

     preprocessors: {
       'app/**/*.js': 'coverage',
       'app/**/*.html': 'ng-html2js',
       'app/resources/*.json'   : ['json_fixtures']
     },

     ngHtml2JsPreprocessor: {
       'moduleName': 'Templates',
       'stripPrefix': 'app/'
     },

     jsonFixturesPreprocessor: {variableName: '__json__'},

     reporters: ['progress', 'coverage'],
     singleRun: false,
     colors: true,
     logLevel: config.LOG_INFO,
   });
 };

Jasmine 单元测试:使用组件和翻译的 Bare Bones

(function() {
  'use strict';

  describe('Home component', function() {
    var rootscope, compile, componentElement;

    beforeEach(module('Templates'));
    beforeEach(module('app'));

    beforeEach(module('pascalprecht.translate', function ($translateProvider) {
      $translateProvider.translations('en', 
        fixture.load('app/resources/locale-en_US.json')
      );

      $translateProvider.preferredLanguage('en');
    }));

    beforeEach(inject(function(_$rootScope_, _$compile_) {
      rootscope = _$rootScope_.$new();
      compile = _$compile_;
    }));

    function getCompiledElement(){
      var element = angular.element('<home-component></home-component>');
      var compiledElement = compile(element)(rootscope);
      rootscope.$digest();
      return compiledElement;
    }

    describe('Home tests', function () {

      it('should have component defined', function () {
        componentElement = getCompiledElement();
        console.log('Compiled component with translations', componentElement);
        expect(componentElement).toBeDefined()
      });
    });
  });
})();

上面的实现将编译您的组件(可以传递绑定等)以及利用翻译器并在控制台的组件中显示您的翻译。

<h1>{{home.title | translate}}</h1>您现在将看到:而不是看到:<h1>Home Page</h1>

于 2018-02-13T22:19:29.840 回答
0

为了使单元测试最有效地解决问题,一个单元应该与其他单元隔离。这样,如果测试变为红色,则可以明确确定失败的单元。这就是为什么最好在单元测试中显式地模拟所有内容并提供固定装置而不是依赖真实数据的原因。

使用第三方单元打破了隔离,因为它们的问题(错误、包版本)无法与单元本身的问题区分开来。这使得调试成本更高。

通过提供模拟过滤器,可以在单元测试中消除对的依赖,该pascalprecht.translate过滤器将以简化、可控的方式执行测试功能。要针对真实数据进行测试,Karma 应该配置为支持模块,例如karma-commonjs预处理器,这样可以直接加载 JSON 数据,而不是通过 XHR 请求。

Lodashget是解析​​点分隔路径的理想选择,类似于翻译服务的做法:

  var translationsEn = require('.../locale-en_US.json');
  ...
  beforeEach(angular.mock.module({ translateFilter: function (path) {
    return _.get(translationsEn, path);
  }));

这将通过简单的解决方法模拟translate过滤器(内部服务)。translateFilter只要值不使用复数等扩展翻译功能,这将起作用。

或者,可以像指南建议的那样修复真正的翻译服务,但使用 CommonJS 加载 JSON 文件:

beforeEach(angular.mock.module(function ($translateProvider) {
  $translateProvider.translations('en', translationsEn);
}));

angular.mock.module在使用 CommonJS 模块时,应该使用它而不是module避免名称冲突。

于 2018-02-13T21:59:55.710 回答