我从这里使用了角度翻译(http://pascalprecht.github.io/angular-translate/),它只是工作正常,但它打破了我的控制器的单元测试错误:
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'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(...);
...
});
如果我在测试控制器中添加它,产品同样错误:
httpMock.when('GET', 'scripts/i18n/locale-en.json').respond(200);
httpMock.flush();
或
httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough();
httpMock.flush();
我发现这篇文章How do I test controllers with Angular Translate initialized in 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();
没有任何反应,但这个错误让我发疯了......
如果您有任何建议
答案 0 :(得分:28)
这是一个已知问题,请按照此处的文档:unit testing angular
解决方案
不幸的是,这个问题是由设计引起的 角翻译。为了解决这些错误,我们所能做的就是 在我们的测试套件中覆盖我们的模块配置,它不会 完全使用异步加载器。当没有异步加载器时 没有XHR,因此没有错误。
那么我们如何在运行时覆盖我们的模块配置呢? 测试套件?在实例化角度模块时,我们总是可以应用 内联函数,作为配置函数执行。这个 配置功能可用于覆盖模块 配置,因为我们可以访问所有提供商。
使用$ provide提供程序,我们可以构建一个自定义加载器工厂, 然后应该使用它而不是静态文件加载器。
beforeEach(module('myApp', function ($provide, $translateProvider) {
$provide.factory('customLoader', function () {
// loader logic goes here
});
$translateProvider.useLoader('customLoader');
}));
请在上面提供的链接中阅读更多内容。
答案 1 :(得分:15)
我们采用了在单元测试中忽略翻译加载器的方法,而不是被迫修改每个spec文件。
一种方法是将加载程序配置分离到一个单独的文件,然后在业力中将其排除。
例如,您可以创建一个文件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的解决方案。)
答案 2 :(得分:12)
我想要一个解决方案,
这就是我最终的结果:
// 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放在全局级别,最好放在测试文件夹中的自己的文件中。它将在每次其他测试之前执行。
答案 3 :(得分:3)
尝试使用测试方法:
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
中的示例答案 4 :(得分:3)
一般情况下,我建议使用标准的翻译加载程序进行单元测试(没有http加载的麻烦),这意味着您可以使用$translateProvider.translations()
提供标签。为什么?因为您不必测试角度转换项目中的远程加载功能。
答案 5 :(得分:3)
我在量角器测试中遇到了这个问题。我的解决方案是模拟这样的翻译:
angular.module('app')
.config(function ($translateProvider) {
$translateProvider.translations('en', {});
$translateProvider.preferredLanguage('en');
})
现在没有下载语言文件,没有字符串被翻译,我只是在规范中测试字符串键:
expect(element(by.css('#title')).getText()).toEqual('TITLE_TEXT');
答案 6 :(得分:1)
没有一个解决方案适合我,但我带来了这些解决方案:
1)如果您需要使用scope.$apply()
,或者应该在测试中处理状态(在$apply()
第二种方法失败后),请覆盖您的应用使用load JSON files
$translateProvider.translations()
方法进行翻译
beforeEach(module(function ($translateProvider) {
$translateProvider.translations('en', readJSON('scripts/i18n/locale-en.json'));
}));
2)如果您的测试控制器依赖于$translate
服务,您可以使用插件load JSON files并将其与$httpBackend
结合使用,以便在angular-translate请求时加载您的语言环境文件。
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
错误。
答案 7 :(得分:1)
我为$ translate
制作了一个简单的模拟服务$translate=function (translation) {
return {
then: function (callback) {
var translated={};
translation.map(function (transl) {
translated[transl]=transl;
});
return callback(translated);
}
}
};
答案 8 :(得分:0)
我使用这种模式。
// 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");
})
})
答案 9 :(得分:0)
在这篇文章的后面,我通过指定Karma根据karma.conf.js
中的此条目仅提供文件来解决这个问题:
files: [
...
{pattern: 'scripts/i18n/*.json', included: false, served: true},
...
]
答案 10 :(得分:0)
2016年的答案是将您的json预处理到您的测试中并正确测试您的指令的翻译工作。
我使用karma-ng-json2js-preprocessor。按照所有步骤设置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');
}));
注意根据插件,它使用您的文件名生成一个camelcased模块名称。您可以在模块的/ lib中使用该函数,但基本上它会移除所有破折号,但在camelCase中删除KEEPS下划线。所以en_us变成了En_us。
您还需要告诉您的测试,它希望该文件为GEt。
$httpBackend.expect('GET', '/l10n/english-translation.json').respond(200);