Подтвердить что ты не робот

Как unit test с angular -транслятом

Я использую angular translate from here (http://pascalprecht.github.io/angular-translate/), и он просто отлично работает, но он прерывает мой контроллер unit test whith Ошибка:

Unexpected request: GET scripts/i18n/locale-en.json

Я не понимаю, почему?

Я использую йоман и испытываю с кармой.

app.js:

'use strict';

(function() {

  angular.module('wbApp', ['authService', 'authUserService', 'checkUserDirective', 'ui.bootstrap', 'pascalprecht.translate'])
    .config(function($routeProvider) {
      $routeProvider
        .when('/', {
          templateUrl: 'views/login.html',
          controller: 'LoginCtrl',
          access: {
            isFree: true
          }
        })
        .when('/main', {
          templateUrl: 'views/main.html',
          controller: 'MainCtrl',
          access: {
            isFree: false
          }
        })
        .otherwise({
          redirectTo: '/'
        });
    });

})();

configTranslate.js:

'use strict';

(function() {

  angular.module('wbApp')
    .config(['$translateProvider',
      function($translateProvider) {

        $translateProvider.useStaticFilesLoader({
            prefix: 'scripts/i18n/locale-',
            suffix: '.json'
        });

        $translateProvider.preferredLanguage('en');

      }]);

})();

karma.conf.js:

files = [

  ...

  'app/bower_components/angular-translate/angular-translate.js',
  'app/bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js',

  ...

];

Контрольный тест:

'use strict';

describe('Controller: LoginCtrl', function() {

  // load the controller module
  beforeEach(module('wbApp'));

  var LoginCtrl, scope, location, httpMock, authUser;

  // Initialize the controller and a mock scope
  beforeEach(inject(function($controller, $rootScope, $location, $httpBackend, AuthUser) {
    authUser = AuthUser;
    location = $location;
    httpMock = $httpBackend;
    scope = $rootScope.$new();

    LoginCtrl = $controller('LoginCtrl', {
      $scope: scope
    });


    httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough();

  }));

  it(...);

  ...

});

если я добавлю это в тестовый контроллер, такая же ошибка продукта:

httpMock.when('GET', 'scripts/i18n/locale-en.json').respond(200);
httpMock.flush();

или

httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough();
httpMock.flush();

Я нахожу этот пост Как тестировать контроллеры с помощью angular Перевести инициализирован в App Config?, но не помог мне:/

Я широко использую $httpBackend в своих тестах, и он отлично работает, но в этом случае он неэффективен. Если я прокомментирую строку:

$translateProvider.preferredLanguage('en');

очевидно, ошибка, если я добавлю в среду выполнения (в моих контроллерах)

$translate.uses(local);

Я получаю ту же ошибку?

Поэтому я перехожу к конфигурации перевода (configTranslate.js) или во время выполнения - это тот же результат:

Unexpected request: GET scripts/i18n/locale-en.json

Вот синтаксис, который я тестировал, либо в "beforeEach (inject (function (...));"

или в тесте "it ('...', function() {...});"

httpMock.expectGET('scripts/i18n/locale-en.json');
httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough();
httpMock.when('GET', 'scripts/i18n/locale-en.json').respond(data);

с концом

httpMock.flush();

Я также попробовал $apply

httpMock.expectGET('scripts/i18n/locale-fr.json');
scope.$apply(function(){
  $translate.uses('fr');
});
httpMock.flush();

ничего не происходит, но эта ошибка сводит меня с ума..

Если у вас есть предложения

4b9b3361

Ответ 1

Это известная проблема, пожалуйста, следуйте документации: модульное тестирование angular

Решение

К сожалению, эта проблема вызвана angular -translate. Чтобы обойти эти ошибки, все, что мы можем сделать, это перезагрузите нашу конфигурацию модуля в нашем наборе тестов, чтобы он не использовать асинхронный загрузчик вообще. Когда нет асинхронного загрузчика, там нет XHR и, следовательно, нет ошибок.

Итак, как мы перезаписываем нашу конфигурацию модуля во время выполнения для нашего тестирование? При создании экземпляра модуля angular мы всегда можем применить встроенная функция, которая выполняется как функция конфигурации. Эта функция конфигурации может использоваться для перезаписывания модулей поскольку у нас есть доступ ко всем провайдерам.

Используя поставщика $provision, мы можем создать пользовательский загрузчик factory, который затем следует использовать вместо загрузчика статических файлов.

beforeEach(module('myApp', function ($provide, $translateProvider) {

  $provide.factory('customLoader', function () {
    // loader logic goes here
  });

  $translateProvider.useLoader('customLoader');

}));

Подробнее читайте в приведенной выше ссылке.

Ответ 2

Мы использовали подход игнорирования загрузчика трансляции в модульных тестах, а не принудительно модифицировать каждый из файлов спецификаций.

Одним из способов сделать это может быть разделение конфигурации загрузчика на отдельный файл и исключение его в карме.

Так, например, вы можете создать файл app-i18n-loader.js(все остальные конфигурации модулей происходят в другом файле):

    angular
    .module('myApp')
    .config(loaderConfig);

loaderConfig.$inject = ['$translateProvider', '$translatePartialLoaderProvider'];

function loaderConfig($translateProvider, $translatePartialLoaderProvider) {

    $translateProvider.useLoader('$translatePartialLoader', {
        urlTemplate: 'assets/i18n/{part}/{lang}.json'
    });

    $translatePartialLoaderProvider.addPart('myApp');
}

И в вашем файле karma.conf.js исключить файл:

        files: [
        'bower_components/angular/angular.js',
        'bower_components/angular-mocks/angular-mocks.js',
        //...
        'bower_components/angular-translate/angular-translate.js',
        'bower_components/angular-translate-loader-partial/angular-translate-loader-partial.js',
        'app/**/*.mdl.js',
        'app/**/*.js'
    ],

    exclude: [
        'app/app-i18n-loader.js'
    ],

(Примечание. Ответ отредактирован для решения, которое не требует grunt/ gulp).

Ответ 3

Мне нужно решение,

  • который не был слишком взломан.
  • который не требовал от меня изменения моего фактического кода приложения,
  • который не будет мешать загрузке дополнительных модулей
  • и, что самое важное, что не потребует от меня изменения каждого одиночный тест.

Вот что я закончил:

// you need to load the 3rd party module first
beforeEach(module('pascalprecht.translate'));
// overwrite useStaticFilesLoader to get rid of request to translation file
beforeEach(module(function ($translateProvider) {
    $translateProvider.useStaticFilesLoader = function () {
    };
}));

Предполагая, что вам не нужны фактические переводы для ваших модульных тестов, это отлично работает. Просто поставьте beforeEach на глобальном уровне, желательно в собственном файле внутри тестовой папки. Он будет выполняться перед каждым другим тестом.

Ответ 4

Попробуйте применить метод тестирования:

it('should ...', function() {
    httpMock.when('GET', 'scripts/i18n/locale-en.json').respond({});
    httpMock.expectGET('scripts/i18n/locale-en.json');
    scope.resetForm(); // Action which fires a http request
    httpMock.flush(); // Flush must be called after the http request
}

См. примеры из Angular docs

Ответ 5

Пожалуйста, посмотрите https://github.com/PascalPrecht/angular-translate/blob/master/test/unit/service/loader-static-files.spec.js как ссылку.

В общем, я бы рекомендовал использовать стандартный загрузчик переводов для модульных тестов (без проблем с загрузкой HTTP), что означает, что вы можете предоставить метки с помощью $translateProvider.translations(). Зачем? Поскольку вам не нужно проверять функциональность удаленной загрузки, которая является частью проекта angular -translate.

Ответ 6

Я столкнулся с этой проблемой с испытаниями транспортировщика. Мое решение заключалось в том, чтобы издеваться над такими переводами:

angular.module('app')
        .config(function ($translateProvider) {
            $translateProvider.translations('en', {});
            $translateProvider.preferredLanguage('en');
        })

Теперь языковые файлы не загружаются, строки не переводятся, и я просто тестирую строковые ключи в спецификациях:

expect(element(by.css('#title')).getText()).toEqual('TITLE_TEXT');

Ответ 7

Ни один из решений не работал у меня, но я пришел с этими решениями:

1) Если вам нужно использовать scope.$apply() или нужно иметь дело с состояниями в вашем тесте (после $apply() второй подход не будет работать), переопределите ваши приложения с помощью метода $translateProvider.translations(), используя плагин для загрузить файлы JSON

beforeEach(module(function ($translateProvider) {
    $translateProvider.translations('en', readJSON('scripts/i18n/locale-en.json'));
}));

2) Если ваш тестируемый контроллер зависит от службы $translate, вы можете использовать плагин для загрузить файлы JSON и объединить его с $httpBackend для загрузки вашего файла локали, когда angular -трансляция запрашивает его.

beforeEach(inject(function (_$httpBackend_) {
    $httpBackend = _$httpBackend_;

    $httpBackend.whenGET('scripts/i18n/locale-en.json').respond(readJSON('scripts/i18n/locale-en.json'));
    $httpBackend.flush();
})));

Обратите внимание, что это должно быть ниже вашего beforeEach(module('myApp')); или вы получите ошибку $injector.

Ответ 8

Я сделал простой mock-сервис для $translate

$translate=function (translation) {
    return {
      then: function (callback) {
        var translated={};
        translation.map(function (transl) {
          translated[transl]=transl;
        });
        return callback(translated);
      }
    }
  };

Пример использования здесь: https://gist.github.com/dam1/5858bdcabb89effca457

Ответ 9

Я использую этот шаблон.

  • ApplicationModule устанавливает обычную конфигурацию angular -translate.
  • тестовый код загружает 'testModule' вместо 'applicationModule'

// application module .js 
(function() {
  'use strict'; 
  
  angular
   .module('applicationModule', [
    'ngAnimate',
    'ngResource',
    'ui.router',
    'pascalprecht.translate'
  ])
  .config(['$stateProvider', '$urlRouterProvider', '$translateProvider', '$translatePartialLoaderProvider', config]);

  function config($stateProvider, $urlRouterProvider, $translateProvider, $translatePartialLoaderProvider) {
    // set routing ... 
        
    $translateProvider.useStaticFilesLoader({
      prefix: 'i18n/locale-',
      suffix: '.json'
    });

    $translateProvider.useMessageFormatInterpolation();
    $translateProvider.fallbackLanguage(['en']);
    $translateProvider
    .registerAvailableLanguageKeys(['en', 'ko'], {
      'en_US': 'en',
      'ko_KR': 'ko'
    })
    .determinePreferredLanguage(navigator.browserLanguage);

            
    $translateProvider.addInterpolation('$translateMessageFormatInterpolation');    
    $translateProvider.useSanitizeValueStrategy('escaped');
  }

})();

Ответ 10

Поздно к таблице с этим, но я обошел это, указав, что Karma просто обслуживает файлы в соответствии с этой записью в karma.conf.js:

files: [
    ...
    {pattern: 'scripts/i18n/*.json', included: false, served: true},
    ...
]

Ответ 11

Ответ 2016 года на этот вопрос заключается в том, чтобы предварительно обработать ваш json в своих тестах и ​​правильно проверить работу перевода с вашими директивами.

Я использую karma-ng-json2js-препроцессор. Следуйте всем инструкциям по настройке вашего karma.conf, затем в тестовом файле, добавьте соответствующий файл в качестве модуля, затем установите эту информацию в $translateProvider.

beforeEach(module('myApp', '/l10n/english-translation.json'));

// Mock translations for this template
beforeEach(module(function($translateProvider, englishTranslation) {
    $translateProvider.translations('en_us', englishTranslation);
    $translateProvider.useSanitizeValueStrategy(null);
    $translateProvider.preferredLanguage('en_us');
}));

Обратите внимание, что в соответствии с плагином он использует ваше имя для генерации имени модуля на вертеле. Вы можете играть с функцией внутри модуля /lib, но в основном она удаляет все тире, но подчеркивает KEEPS в camelCase. Итак, en_us становится En_us.

Вам также нужно будет сообщить вашему тесту, что он ожидает, что этот файл будет представлять собой GEt.

    $httpBackend.expect('GET', '/l10n/english-translation.json').respond(200);