我们的应用程序当前有大约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(定义了全局moduleinject 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');
});

09-03 17:15