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:

committed by
Miško Hevery

parent
1f79c827a0
commit
6d861f240b
@ -25,6 +25,7 @@ ts_library(
|
||||
"//packages/platform-browser/testing",
|
||||
"//packages/platform-server",
|
||||
"//packages/private/testing",
|
||||
"//packages/router",
|
||||
"@npm//rxjs",
|
||||
"@npm//zone.js",
|
||||
],
|
||||
|
@ -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[] = [];
|
||||
|
64
packages/core/test/acceptance/router_integration_spec.ts
Normal file
64
packages/core/test/acceptance/router_integration_spec.ts
Normal 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',
|
||||
]);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user