我们的应用程序当前有大约4,500+个现有的Angular 1测试。现在,我们使用UpgradeModule
合并了Angular 2,以降级Angular 2服务,该服务在我们的应用程序的run()方法中使用。这将导致所有测试失败,并出现Error: [$injector:unpr] Unknown Provider $$angularInjectorProvider
错误。
我创建了一个plnkr来演示此问题(http://plnkr.co/edit/XuMYBr9xInqq18Kr6EAs?p=preview)。
基本上,Angular 1模块如下所示:
// angular1.module.ts
angular.module( 'testApp' )
.run( [ 'Angular2Service', Angular2Service => { // injecting downgraded service
Angular2Service.showTestMessage();
} ] );
Angular2Service
被降级的地方:// app.module.ts
angular.module( 'testApp' )
.factory( 'Angular2Service', downgradeInjectable( Angular2Service ) );
@NgModule({
imports: [ BrowserModule, UpgradeModule ],
providers : [ Angular2Service ]
})
export class AppModule {
ngDoBootstrap() {}
}
最初,到目前为止,执行测试时我收到了
'Angular2Service'
本身的未知提供程序错误,因此我添加了一个beforeEach()
来编译AppModule
中的所有内容:beforeEach( async( () => {
TestBed.configureTestingModule( {
imports : [ AppModule ]
} )
.compileComponents();
} ) );
这就是我遇到
Error: [$injector:unpr] Unknown Provider $$angularInjectorProvider
错误的地方。正在执行的测试本身纯粹是Angular 1测试,如果我不将
Angular2Service
注入(inject)run()方法,则该测试通过:describe( 'testComponent', () => {
var $compile,
$scope;
beforeEach( module( 'testApp' ) );
beforeEach( inject( $injector => {
$compile = $injector.get( '$compile' );
$scope = $injector.get( '$rootScope' ).$new();
} ) );
it( 'should show the text "Test Component" in the DOM', () => {
var element = $compile( '<test-component></test-component>' )( $scope );
$scope.$apply();
expect( element[ 0 ].innerHTML ).toBe( 'Test Component' );
} );
} );
我希望可以对此进行修复,以便我们所有的纯Angular 1测试都可以继续保持不变,但是如果需要的话,我也可以对其进行更新。任何帮助,将不胜感激!
http://plnkr.co/edit/XuMYBr9xInqq18Kr6EAs?p=preview
最佳答案
我遇到了同样的问题,并提出了解决方案。这不是最好的方法,但是它只是解决了迁移阶段的问题。
我确定您使用的是upgrade-static.umd.js
dist文件,而不是upgrade.umd.js
。静态代码旨在与ngc AoT编译一起使用,我们应该在生产应用程序中使用它。如果您深入研究它的代码,就可以很容易地发现它定义了一个名为$$UpgradeModule
的新angularjs模块,该模块注册了一个名为$$angularInjector
的值提供程序(上述错误中的那个)-该$$angularInjector
负责将Angular模块注入(inject)angularjs。
问题
您以前的angularjs测试不会启动$$UpgradeModule
,因此其提供程序不可注入(inject)。请注意,angular-mocks
(定义了全局module
和inject
fns)为 Jasmine 和mocka做一些补丁,以在套件之间提供某种注入(inject)隔离。
解决方案
您每次只需要在测试将直接(或间接)注入(inject)降级的提供程序的代码时,只需在第一个beforeEach调用module('$$UpgradeModule')
。
但是,这不是那么简单:)。实际上$$UpgradeModule
是在UpgradeModule.boorstrap
函数中声明的。这意味着您需要在进行任何测试之前引导整个应用程序(angularjs和Angular)(或更严格的形式-引导根模块)。这不是很好,因为我们要完全隔离地测试模块和提供程序。
另一种解决方案
一种替代方法是使用UpgradeAdapter
中定义的upgrade.umd.js
。老实说,我没有尝试过-但是从代码看来,它可以仅启动我们想要的模块,而无需引导整个应用程序。但是我认为我们可能需要使用UpgradeAdapter
方法对测试进行降级以使其正常工作。
编辑
例子:
要进行引导,您需要在导入测试文件之前,将应用程序模块为SystemJs导入。因此,您的karma-stest-shim.js
将包含类似的内容
System.import('systemjs.config.js')
.then(importSystemJsExtras)
.then(importApp)
.then(initTestBed)
.then(initTesting);
function importApp() {
return Promise.all(
[
System.import('app'),
]
)
}
这将对两个版本都执行常规引导,并定义
$$upgradeModule
。然后在将注入(inject)降级的提供程序的任何测试中
beforeEach(function () {
// the ng1 module for the downgraded provider
module('services');
// the trick is here
module('$$UpgradeModule');
});