fix(ivy): module with providers are processed too early (#30688)

Currently with Ivy, `ModuleWithProvider` providers are processed in order
of declaration in the `NgModule` imports. This technically makes makes
sense but is a potential breaking change as `ModuleWithProvider` providers
are processed after all imported modules in View Engine.

In order to keep the behavior of View Engine, the `r3_injector` is updated
to no longer process `ModuleWithProvider` providers egarly.

Resolves FW-1349

PR Close #30688
This commit is contained in:
Paul Gschwendtner
2019-05-27 20:34:01 +02:00
committed by Miško Hevery
parent 1f79c827a0
commit 6d861f240b
5 changed files with 156 additions and 16 deletions

View File

@ -25,6 +25,7 @@ ts_library(
"//packages/platform-browser/testing",
"//packages/platform-server",
"//packages/private/testing",
"//packages/router",
"@npm//rxjs",
"@npm//zone.js",
],

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, Injector, Input, LOCALE_ID, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef} from '@angular/core';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef} from '@angular/core';
import {ViewRef} from '@angular/core/src/render3/view_ref';
import {TestBed} from '@angular/core/testing';
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
@ -31,6 +31,32 @@ describe('di', () => {
});
});
describe('multi providers', () => {
it('should process ModuleWithProvider providers after module imports', () => {
const testToken = new InjectionToken<string[]>('test-multi');
@NgModule({providers: [{provide: testToken, useValue: 'A', multi: true}]})
class TestModuleA {
}
@NgModule({providers: [{provide: testToken, useValue: 'B', multi: true}]})
class TestModuleB {
}
TestBed.configureTestingModule({
imports: [
{
ngModule: TestModuleA,
providers: [{provide: testToken, useValue: 'C', multi: true}],
},
TestModuleB,
]
});
expect(TestBed.get(testToken) as string[]).toEqual(['A', 'B', 'C']);
});
});
describe('directive injection', () => {
let log: string[] = [];

View File

@ -0,0 +1,64 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {APP_BASE_HREF} from '@angular/common';
import {NgModule} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {Router, RouterModule} from '@angular/router';
describe('router integration acceptance', () => {
// Test case that ensures that we don't regress in multi-provider ordering
// which is leveraged in the router. See: FW-1349
it('should have correct order for multiple routes declared in different modules', () => {
@NgModule({
imports: [
RouterModule.forChild([
{path: '1a:1', redirectTo: ''},
{path: '1a:2', redirectTo: ''},
]),
],
})
class Level1AModule {
}
@NgModule({
imports: [
RouterModule.forChild([
{path: '1b:1', redirectTo: ''},
{path: '1b:2', redirectTo: ''},
]),
],
})
class Level1BModule {
}
@NgModule({
imports: [
RouterModule.forRoot([{path: 'root', redirectTo: ''}]),
Level1AModule,
Level1BModule,
],
providers: [
{provide: APP_BASE_HREF, useValue: '/'},
]
})
class RootModule {
}
TestBed.configureTestingModule({
imports: [RootModule],
});
expect((TestBed.get(Router) as Router).config.map(r => r.path)).toEqual([
'1a:1',
'1a:2',
'1b:1',
'1b:2',
'root',
]);
});
});