webentwicklung-frage-antwort-db.com.de

Wie führen Sie einen Einheitentest mit Winkelübersetzen durch?

Ich habe Winkelübersetzen von hier verwendet ( http://pascalprecht.github.io/angular-translate/ ) und es funktioniert einfach, aber es bricht den Unit-Test meines Controllers mit Fehler:

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

Ich verstehe nicht warum?

Ich benutze Yeoman und teste mit Karma.

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',

  ...

];

controller-Test:

'use strict';

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

  // load the controller's 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(...);

  ...

});

wenn ich dies in Test Controller hinzufüge, wird der gleiche Fehler angezeigt:

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

oder

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

ich finde diesen Beitrag Wie teste ich Controller mit Angular Translate, die in App Config initialisiert wurden? aber mir hat nicht geholfen: /

Ich benutze $ httpBackend ausgiebig in meinen Tests und es funktioniert gut, aber in diesem Fall ist es unwirksam. Wenn ich die Zeile kommentiere:

$translateProvider.preferredLanguage('en');

natürlich ein Fehler, wenn ich zur Laufzeit (in meinen Controllern) hinzufüge

$translate.uses(local);

Ich ende mit dem gleichen Fehler?

Also wende ich mich an die Übersetzungskonfiguration (configTranslate.js) oder zur Laufzeit ist das gleiche Ergebnis:

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

Hier ist die Syntax, die ich getestet habe, entweder in "beforeEach (inject (function (...));"

oder in einem Test "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);

mit am Ende

httpMock.flush();

Ich habe auch versucht ein $ bewerben

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

nichts passiert, immer noch dieser Fehler macht mich verrückt ..

Wenn Sie einen Vorschlag haben

40
bin

es ist ein bekanntes Problem, bitte folgen Sie der Dokumentation hier: Einheitstestwinkel

Die Lösung 

Leider wird dieses Problem durch das Design von .__ verursacht. Winkelübersetzen. Um diese Fehler zu umgehen, können wir nur Überschreiben Sie unsere Modulkonfiguration in unserer Testsuite. Verwenden Sie asynchronen Lader überhaupt. Wenn kein asynchroner Lader vorhanden ist, Es gibt kein XHR und daher keinen Fehler.

Wie überschreiben wir unsere Modulkonfiguration zur Laufzeit für unser Testsuite? Wenn Sie ein Winkelmodul instanziieren, können Sie immer eine Inline-Funktion, die als Konfigurationsfunktion ausgeführt wird. Diese Konfigurationsfunktion kann zum Überschreiben der Module verwendet werden Konfiguration, da wir Zugriff auf alle Anbieter haben.

Mit dem Provider $ Provider können wir eine benutzerdefinierte Loader-Factory erstellen, Diese sollte dann anstelle des statischen Dateiladers verwendet werden.

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

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

  $translateProvider.useLoader('customLoader');

}));

Bitte lesen Sie mehr im obigen Link.

28
nolimit

Wir haben den Ansatz verfolgt, das Übersetzungsladeprogramm in Komponententests zu ignorieren, anstatt jede Spezifikationsdatei zu ändern.

Eine Möglichkeit, dies zu tun, besteht darin, die Loader-Konfiguration in eine separate Datei zu trennen und sie dann in Karma auszuschließen.

So können Sie beispielsweise eine Datei app-i18n-loader.js erstellen (alle anderen Modulkonfigurationen finden in einer anderen Datei statt):

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

Und in Ihrer karma.conf.js schließen Sie die Datei aus:

        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'
    ],

(Hinweis: Beantworten Sie die Antwort auf eine Lösung, für die kein Grunzen/Schlucken erforderlich ist).

15
Erez Cohen

Ich wollte eine Lösung 

  1. das war nicht zu hackig 
  2. was mich nicht zwang, meinen eigentlichen Anwendungscode zu ändern, 
  3. was die Fähigkeit, zusätzliche Module zu laden, nicht beeinträchtigen würde 
  4. und am wichtigsten, was würde nicht erfordern, dass ich jeden einzelnen Test __.

Dies ist, was ich endete mit: 

// 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 () {
    };
}));

Vorausgesetzt, Sie benötigen nicht die eigentlichen Übersetzungen für Ihre Komponententests, funktioniert dies hervorragend. Legen Sie das beforeEach einfach auf eine globale Ebene, vorzugsweise in eine eigene Datei im Testordner. Sie wird dann vor jedem zweiten Test ausgeführt.

12

Dieses Problem ist bei Winkelstücktests aufgetreten. Meine Lösung bestand darin, Übersetzungen wie folgt zu simulieren:

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

Jetzt werden keine Sprachdateien heruntergeladen, keine Zeichenketten werden übersetzt und ich teste nur anhand der Zeichenfolgenschlüssel in den Spezifikationen:

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

Bitte schauen Sie als Referenz nach https://github.com/PascalPrecht/angular-translate/blob/master/test/unit/service/loader-static-files.spec.js .

Im Allgemeinen würde ich die Verwendung eines Standard-Übersetzungsladeprogramms für Komponententests (ohne den Aufwand von http-Ladungen) empfehlen, was bedeutet, dass Sie die Beschriftungen mit $translateProvider.translations() versehen können. Warum? Weil Sie die Fernladefunktionalität, die Teil des Projektes für die Winkelübersetzung ist, nicht testen müssen.

3
knalli

Versuchen Sie, die Methode zu testen:

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
}

Siehe Beispiele aus Angular docs

3
Matti Lehtinen

Keine der Lösungen funktionierte für mich, aber ich kam mit diesen Lösungen:

1) Wenn Sie scope.$apply() verwenden müssen oder sich in Ihrem Test mit Status befassen sollten (nach $apply() funktioniert der 2. Ansatz nicht), überschreiben Sie die Übersetzungen Ihrer App mit $translateProvider.translations() -Methode, die ein Plugin verwendet, um JSON-Dateien zu laden

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

2) Wenn Ihr getesteter Controller vom Dienst $translate Abhängt, können Sie ein Plugin verwenden, um JSON-Dateien laden und es mit $httpBackend Zu kombinieren, um Ihre Gebietsschemadatei zu laden, wenn winklig- übersetze Anfragen dazu.

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

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

Beachten Sie, dass dies unter Ihrem beforeEach(module('myApp')); liegen sollte, da sonst ein $injector - Fehler angezeigt wird.

1
Bruno Peres

Ich habe einen einfachen Mock-Service für $ translate gemacht

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

Nutzungsbeispiel hier: https://Gist.github.com/dam1/5858bdcabb89effca457

1
dam1

Die Antwort darauf lautet 2016, Ihren Json in Ihre Tests vorzubereiten und die Übersetzungsarbeit Ihrer Richtlinien entsprechend zu testen. 

Ich verwende karma-ng-json2js-Präprozessor. Befolgen Sie alle Schritte, um Ihre karma.conf in Ihrer Testdatei einzurichten, stellen Sie die entsprechende Datei als Modul voran und stellen Sie diese Informationen in $ translateProvider ein.

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

Beachten Sie entsprechend dem Plugin, dass es Ihren Dateinamen verwendet, um einen Kamelennamen zu generieren. Sie können mit der Funktion in/lib des Moduls spielen, im Grunde werden jedoch alle Bindestriche entfernt, aber KEEPS unterstrichen in einem camelCase. So wird en_us zu En_us.

Sie müssen Ihrem Test auch mitteilen, dass er diese Datei als GEt erwartet.

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

Ich benutze dieses Muster.

  • ApplicationModule setzt reguläre Winkelübersetzungskonfiguration.
  • testcode lädt 'testModule' anstelle von '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');
  }

})();

// test.module.js
(function() {
  'use strict';

  angular
    .module('testModule', ['applicationModule'])
    .config(['$translateProvider', '$translatePartialLoaderProvider', config])
    .run(['$httpBackend', run]);

  function config($translateProvider, $translatePartialLoaderProvider) {
    $translateProvider.useLoader('$translatePartialLoader', {
        urlTemplate: 'i18n/locale-en.json'
    });
    $translatePartialLoaderProvider.addPart('applicationModule');
  }

  function run($httpBackend) {
    $httpBackend.when('GET', 'i18n/locale-en.json').respond(200);
  }

})();


// someDirective.spec.js
describe("a3Dashboard", function() {
    beforeEach(module("testModule"))

    var element, $scope;
    beforeEach(inject(function($compile, $rootScope) {
        $scope = $rootScope;
        element = angular.element("<div>{{2 + 2}}</div>");
        $compile(element)($rootScope)
    }))

    it('should equal 4', function() {
      $scope.$digest();
      expect(element.html()).toBe("4");
    })

})
0
nulpulum

Spät am Tisch damit, aber ich bin damit umgekommen, indem ich angab, dass Karma die Dateien einfach gemäß diesem Eintrag in karma.conf.js bereitstellt:

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