fix(router): incorrect injector is used when instantiating components loaded lazily (#12817)

This commit is contained in:
Victor Savkin
2016-11-11 17:12:00 -08:00
committed by Victor Berchet
parent 69dfcf7385
commit 52be848f94
7 changed files with 110 additions and 75 deletions

View File

@ -143,7 +143,8 @@ describe('applyRedirects', () => {
describe('lazy loading', () => {
it('should load config on demand', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {
load: (injector: any, p: any) => {
if (injector !== 'providedInjector') throw 'Invalid Injector';
@ -171,7 +172,8 @@ describe('applyRedirects', () => {
it('should load when all canLoad guards return true', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const guard = () => true;
@ -191,7 +193,8 @@ describe('applyRedirects', () => {
it('should not load when any canLoad guards return false', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const trueGuard = () => true;
@ -216,7 +219,8 @@ describe('applyRedirects', () => {
it('should not load when any canLoad guards is rejected (promises)', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const trueGuard = () => Promise.resolve(true);
@ -237,7 +241,8 @@ describe('applyRedirects', () => {
it('should work with objects implementing the CanLoad interface', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: 'b', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const guard = {canLoad: () => Promise.resolve(true)};
@ -254,7 +259,8 @@ describe('applyRedirects', () => {
it('should work with absolute redirects', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
@ -269,7 +275,8 @@ describe('applyRedirects', () => {
it('should load the configuration only once', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
let called = false;
const loader = {
@ -295,7 +302,8 @@ describe('applyRedirects', () => {
it('should load the configuration of a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
@ -308,7 +316,8 @@ describe('applyRedirects', () => {
it('should load the configuration after a local redirect from a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
@ -322,7 +331,8 @@ describe('applyRedirects', () => {
it('should load the configuration after an absolute redirect from a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig(
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver');
[{path: '', component: ComponentB}], <any>'stubInjector', <any>'stubFactoryResolver',
<any>'injectorFactory');
const loader = {load: (injector: any, p: any) => of (loadedConfig)};

View File

@ -2024,54 +2024,78 @@ describe('Integration', () => {
expect(location.path()).toEqual('/lazy2/loaded');
})));
it('should use the injector of the lazily-loaded configuration',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
class LazyLoadedServiceDefinedInModule {}
class LazyLoadedServiceDefinedInCmp {}
@Component({selector: 'lazy', template: 'lazy-loaded'})
class LazyLoadedChildComponent {
constructor(service: LazyLoadedServiceDefinedInCmp) {}
}
describe('should use the injector of the lazily-loaded configuration', () => {
class LazyLoadedServiceDefinedInModule {}
class LazyLoadedServiceDefinedInCmp {}
@Component({
selector: 'lazy',
template: '<router-outlet></router-outlet>',
providers: [LazyLoadedServiceDefinedInCmp]
})
class LazyLoadedParentComponent {
constructor(service: LazyLoadedServiceDefinedInModule) {}
}
@Component({
selector: 'eager-parent',
template: 'eager-parent <router-outlet></router-outlet>',
})
class EagerParentComponent {
}
@NgModule({
declarations: [LazyLoadedParentComponent, LazyLoadedChildComponent],
imports: [RouterModule.forChild([{
path: '',
children: [{
path: 'loaded',
component: LazyLoadedParentComponent,
children: [{path: 'child', component: LazyLoadedChildComponent}]
}]
}])],
providers: [LazyLoadedServiceDefinedInModule]
})
class LoadedModule {
}
@Component({selector: 'lazy-parent', template: 'lazy-parent <router-outlet></router-outlet>'})
class LazyParentComponent {
}
loader.stubbedModules = {expected: LoadedModule};
@Component({selector: 'lazy-child', template: 'lazy-child'})
class LazyChildComponent {
constructor(
lazy: LazyParentComponent, // should be able to inject lazy/direct parent
lazyService: LazyLoadedServiceDefinedInModule, // should be able to inject lazy service
eager:
EagerParentComponent // should use the injector of the location to create a parent
) {}
}
const fixture = createRoot(router, RootCmp);
@NgModule({
declarations: [LazyParentComponent, LazyChildComponent],
imports: [RouterModule.forChild([{
path: '',
children: [{
path: 'lazy-parent',
component: LazyParentComponent,
children: [{path: 'lazy-child', component: LazyChildComponent}]
}]
}])],
providers: [LazyLoadedServiceDefinedInModule]
})
class LoadedModule {
}
router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]);
@NgModule({
declarations: [EagerParentComponent],
entryComponents: [EagerParentComponent],
imports: [RouterModule]
})
class TestModule {
}
router.navigateByUrl('/lazy/loaded/child');
advance(fixture);
beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); });
expect(location.path()).toEqual('/lazy/loaded/child');
expect(fixture.nativeElement).toHaveText('lazy-loaded');
})));
it('should use the injector of the lazily-loaded configuration',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
loader.stubbedModules = {expected: LoadedModule};
const fixture = createRoot(router, RootCmp);
router.resetConfig([{
path: 'eager-parent',
component: EagerParentComponent,
children: [{path: 'lazy', loadChildren: 'expected'}]
}]);
router.navigateByUrl('/eager-parent/lazy/lazy-parent/lazy-child');
advance(fixture);
expect(location.path()).toEqual('/eager-parent/lazy/lazy-parent/lazy-child');
expect(fixture.nativeElement).toHaveText('eager-parent lazy-parent lazy-child');
})));
});
it('works when given a callback',
fakeAsync(inject(