diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index b89bae4bb8..871b64e623 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -34,10 +34,15 @@ import {createElementRef} from './view_engine_compatibility'; import {RootViewRef, ViewRef} from './view_ref'; export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver { + /** + * @param ngModule The NgModuleRef to which all resolved factories are bound. + */ + constructor(private ngModule?: viewEngine_NgModuleRef) { super(); } + resolveComponentFactory(component: Type): viewEngine_ComponentFactory { ngDevMode && assertComponentType(component); const componentDef = getComponentDef(component) !; - return new ComponentFactory(componentDef); + return new ComponentFactory(componentDef, this.ngModule); } } @@ -75,10 +80,13 @@ function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injec get: (token: Type| InjectionToken, notFoundValue?: T): T => { const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR); - if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { + if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || + notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { // Return the value from the root element injector when // - it provides it // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) + // - the module injector should not be checked + // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) return value; } @@ -103,7 +111,12 @@ export class ComponentFactory extends viewEngine_ComponentFactory { return toRefArray(this.componentDef.outputs); } - constructor(private componentDef: ComponentDef) { + /** + * @param componentDef The component definition. + * @param ngModule The NgModuleRef to which the factory is bound. + */ + constructor( + private componentDef: ComponentDef, private ngModule?: viewEngine_NgModuleRef) { super(); this.componentType = componentDef.type; this.selector = componentDef.selectors[0][0] as string; @@ -114,6 +127,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { injector: Injector, projectableNodes?: any[][]|undefined, rootSelectorOrNode?: any, ngModule?: viewEngine_NgModuleRef|undefined): viewEngine_ComponentRef { const isInternalRootView = rootSelectorOrNode === undefined; + ngModule = ngModule || this.ngModule; const rootViewInjector = ngModule ? createChainedInjector(injector, ngModule.injector) : injector; diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index 51f5810249..26952189d1 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector} from '../di/injector'; +import {INJECTOR, Injector} from '../di/injector'; +import {InjectFlags} from '../di/injector_compatibility'; import {StaticProvider} from '../di/provider'; import {createInjector} from '../di/r3_injector'; import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver'; @@ -14,27 +15,29 @@ import {InternalNgModuleRef, NgModuleFactory as viewEngine_NgModuleFactory, NgMo import {NgModuleDef} from '../metadata/ng_module'; import {Type} from '../type'; import {stringify} from '../util'; + import {assertDefined} from './assert'; import {ComponentFactoryResolver} from './component_ref'; import {getNgModuleDef} from './definition'; export interface NgModuleType { ngModuleDef: NgModuleDef; } -export const COMPONENT_FACTORY_RESOLVER: StaticProvider = { +const COMPONENT_FACTORY_RESOLVER: StaticProvider = { provide: viewEngine_ComponentFactoryResolver, - useFactory: () => new ComponentFactoryResolver(), - deps: [], + useClass: ComponentFactoryResolver, + deps: [viewEngine_NgModuleRef], }; export class NgModuleRef extends viewEngine_NgModuleRef implements InternalNgModuleRef { // tslint:disable-next-line:require-internal-with-underscore _bootstrapComponents: Type[] = []; - injector: Injector; - componentFactoryResolver: viewEngine_ComponentFactoryResolver; + // tslint:disable-next-line:require-internal-with-underscore + _r3Injector: Injector; + injector: Injector = this; instance: T; destroyCbs: (() => void)[]|null = []; - constructor(ngModuleType: Type, parentInjector: Injector|null) { + constructor(ngModuleType: Type, public _parent: Injector|null) { super(); const ngModuleDef = getNgModuleDef(ngModuleType); ngDevMode && assertDefined( @@ -43,14 +46,26 @@ export class NgModuleRef extends viewEngine_NgModuleRef implements Interna this._bootstrapComponents = ngModuleDef !.bootstrap; const additionalProviders: StaticProvider[] = [ - COMPONENT_FACTORY_RESOLVER, { + { provide: viewEngine_NgModuleRef, useValue: this, - } + }, + COMPONENT_FACTORY_RESOLVER ]; - this.injector = createInjector(ngModuleType, parentInjector, additionalProviders); - this.instance = this.injector.get(ngModuleType); - this.componentFactoryResolver = new ComponentFactoryResolver(); + this._r3Injector = createInjector(ngModuleType, _parent, additionalProviders); + this.instance = this.get(ngModuleType); + } + + get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND, + injectFlags: InjectFlags = InjectFlags.Default): any { + if (token === Injector || token === viewEngine_NgModuleRef || token === INJECTOR) { + return this; + } + return this._r3Injector.get(token, notFoundValue, injectFlags); + } + + get componentFactoryResolver(): viewEngine_ComponentFactoryResolver { + return this.get(viewEngine_ComponentFactoryResolver); } destroy(): void { diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index 779d1de878..09d509678e 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -235,7 +235,7 @@ export function createContainerRef( injector?: Injector|undefined, projectableNodes?: any[][]|undefined, ngModuleRef?: viewEngine_NgModuleRef|undefined): viewEngine_ComponentRef { const contextInjector = injector || this.parentInjector; - if (!ngModuleRef && contextInjector) { + if (!ngModuleRef && (componentFactory as any).ngModule == null && contextInjector) { ngModuleRef = contextInjector.get(viewEngine_NgModuleRef, null); } diff --git a/packages/core/test/render3/component_ref_spec.ts b/packages/core/test/render3/component_ref_spec.ts index 6965946ac9..8b832a912e 100644 --- a/packages/core/test/render3/component_ref_spec.ts +++ b/packages/core/test/render3/component_ref_spec.ts @@ -187,5 +187,87 @@ describe('ComponentFactory', () => { expect(mSanitizerFactorySpy).toHaveBeenCalled(); }); }); + + describe('(when the factory is bound to a `ngModuleRef`)', () => { + it('should retrieve `RendererFactory2` from the specified injector first', () => { + const injector = Injector.create([ + {provide: RendererFactory2, useValue: {createRenderer: createRenderer2Spy}}, + ]); + (cf as any).ngModule = { + injector: Injector.create([ + {provide: RendererFactory2, useValue: {createRenderer: createRenderer3Spy}}, + ]) + }; + + cf.create(injector); + + expect(createRenderer2Spy).toHaveBeenCalled(); + expect(createRenderer3Spy).not.toHaveBeenCalled(); + }); + + it('should retrieve `RendererFactory2` from the `ngModuleRef` if not provided by the injector', + () => { + const injector = Injector.create([]); + (cf as any).ngModule = { + injector: Injector.create([ + {provide: RendererFactory2, useValue: {createRenderer: createRenderer2Spy}}, + ]) + }; + + cf.create(injector); + + expect(createRenderer2Spy).toHaveBeenCalled(); + expect(createRenderer3Spy).not.toHaveBeenCalled(); + }); + + it('should fall back to `domRendererFactory3` if `RendererFactory2` is not provided', () => { + const injector = Injector.create([]); + (cf as any).ngModule = {injector: Injector.create([])}; + + cf.create(injector); + + expect(createRenderer2Spy).not.toHaveBeenCalled(); + expect(createRenderer3Spy).toHaveBeenCalled(); + }); + + it('should retrieve `Sanitizer` from the specified injector first', () => { + const iSanitizerFactorySpy = + jasmine.createSpy('Injector#sanitizerFactory').and.returnValue({}); + const injector = Injector.create([ + {provide: Sanitizer, useFactory: iSanitizerFactorySpy, deps: []}, + ]); + + const mSanitizerFactorySpy = + jasmine.createSpy('NgModuleRef#sanitizerFactory').and.returnValue({}); + (cf as any).ngModule = { + injector: Injector.create([ + {provide: Sanitizer, useFactory: mSanitizerFactorySpy, deps: []}, + ]) + }; + + cf.create(injector); + + expect(iSanitizerFactorySpy).toHaveBeenCalled(); + expect(mSanitizerFactorySpy).not.toHaveBeenCalled(); + }); + + it('should retrieve `Sanitizer` from the `ngModuleRef` if not provided by the injector', + () => { + const injector = Injector.create([]); + + const mSanitizerFactorySpy = + jasmine.createSpy('NgModuleRef#sanitizerFactory').and.returnValue({}); + (cf as any).ngModule = { + injector: Injector.create([ + {provide: Sanitizer, useFactory: mSanitizerFactorySpy, deps: []}, + ]) + }; + + + cf.create(injector); + + expect(mSanitizerFactorySpy).toHaveBeenCalled(); + }); + }); }); }); diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 31eddaa061..412eb2fd8b 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -3561,94 +3561,93 @@ describe('Integration', () => { expect(fixture.nativeElement).toHaveText('lazy-loaded-parent [lazy-loaded-child]'); }))); - fixmeIvy('FW-646: Directive providers don\'t support primitive types as DI tokens') - .it('should have 2 injector trees: module and element', - fakeAsync(inject( - [Router, Location, NgModuleFactoryLoader], - (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Component({ - selector: 'lazy', - template: 'parent[]', - viewProviders: [ - {provide: 'shadow', useValue: 'from parent component'}, - ], - }) - class Parent { - } + it('should have 2 injector trees: module and element', + fakeAsync(inject( + [Router, Location, NgModuleFactoryLoader], + (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { + @Component({ + selector: 'lazy', + template: 'parent[]', + viewProviders: [ + {provide: 'shadow', useValue: 'from parent component'}, + ], + }) + class Parent { + } - @Component({selector: 'lazy', template: 'child'}) - class Child { - } + @Component({selector: 'lazy', template: 'child'}) + class Child { + } - @NgModule({ - declarations: [Parent], - imports: [RouterModule.forChild([{ - path: 'parent', - component: Parent, - children: [ - {path: 'child', loadChildren: 'child'}, - ] - }])], - providers: [ - {provide: 'moduleName', useValue: 'parent'}, - {provide: 'fromParent', useValue: 'from parent'}, - ], - }) - class ParentModule { - } + @NgModule({ + declarations: [Parent], + imports: [RouterModule.forChild([{ + path: 'parent', + component: Parent, + children: [ + {path: 'child', loadChildren: 'child'}, + ] + }])], + providers: [ + {provide: 'moduleName', useValue: 'parent'}, + {provide: 'fromParent', useValue: 'from parent'}, + ], + }) + class ParentModule { + } - @NgModule({ - declarations: [Child], - imports: [RouterModule.forChild([{path: '', component: Child}])], - providers: [ - {provide: 'moduleName', useValue: 'child'}, - {provide: 'fromChild', useValue: 'from child'}, - {provide: 'shadow', useValue: 'from child module'}, - ], - }) - class ChildModule { - } + @NgModule({ + declarations: [Child], + imports: [RouterModule.forChild([{path: '', component: Child}])], + providers: [ + {provide: 'moduleName', useValue: 'child'}, + {provide: 'fromChild', useValue: 'from child'}, + {provide: 'shadow', useValue: 'from child module'}, + ], + }) + class ChildModule { + } - loader.stubbedModules = { - parent: ParentModule, - child: ChildModule, - }; + loader.stubbedModules = { + parent: ParentModule, + child: ChildModule, + }; - const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'parent'}]); - router.navigateByUrl('/lazy/parent/child'); - advance(fixture); - expect(location.path()).toEqual('/lazy/parent/child'); - expect(fixture.nativeElement).toHaveText('parent[child]'); + const fixture = createRoot(router, RootCmp); + router.resetConfig([{path: 'lazy', loadChildren: 'parent'}]); + router.navigateByUrl('/lazy/parent/child'); + advance(fixture); + expect(location.path()).toEqual('/lazy/parent/child'); + expect(fixture.nativeElement).toHaveText('parent[child]'); - const pInj = fixture.debugElement.query(By.directive(Parent)).injector !; - const cInj = fixture.debugElement.query(By.directive(Child)).injector !; + const pInj = fixture.debugElement.query(By.directive(Parent)).injector !; + const cInj = fixture.debugElement.query(By.directive(Child)).injector !; - expect(pInj.get('moduleName')).toEqual('parent'); - expect(pInj.get('fromParent')).toEqual('from parent'); - expect(pInj.get(Parent)).toBeAnInstanceOf(Parent); - expect(pInj.get('fromChild', null)).toEqual(null); - expect(pInj.get(Child, null)).toEqual(null); + expect(pInj.get('moduleName')).toEqual('parent'); + expect(pInj.get('fromParent')).toEqual('from parent'); + expect(pInj.get(Parent)).toBeAnInstanceOf(Parent); + expect(pInj.get('fromChild', null)).toEqual(null); + expect(pInj.get(Child, null)).toEqual(null); - expect(cInj.get('moduleName')).toEqual('child'); - expect(cInj.get('fromParent')).toEqual('from parent'); - expect(cInj.get('fromChild')).toEqual('from child'); - expect(cInj.get(Parent)).toBeAnInstanceOf(Parent); - expect(cInj.get(Child)).toBeAnInstanceOf(Child); - // The child module can not shadow the parent component - expect(cInj.get('shadow')).toEqual('from parent component'); + expect(cInj.get('moduleName')).toEqual('child'); + expect(cInj.get('fromParent')).toEqual('from parent'); + expect(cInj.get('fromChild')).toEqual('from child'); + expect(cInj.get(Parent)).toBeAnInstanceOf(Parent); + expect(cInj.get(Child)).toBeAnInstanceOf(Child); + // The child module can not shadow the parent component + expect(cInj.get('shadow')).toEqual('from parent component'); - const pmInj = pInj.get(NgModuleRef).injector; - const cmInj = cInj.get(NgModuleRef).injector; + const pmInj = pInj.get(NgModuleRef).injector; + const cmInj = cInj.get(NgModuleRef).injector; - expect(pmInj.get('moduleName')).toEqual('parent'); - expect(cmInj.get('moduleName')).toEqual('child'); + expect(pmInj.get('moduleName')).toEqual('parent'); + expect(cmInj.get('moduleName')).toEqual('child'); - expect(pmInj.get(Parent, '-')).toEqual('-'); - expect(cmInj.get(Parent, '-')).toEqual('-'); - expect(pmInj.get(Child, '-')).toEqual('-'); - expect(cmInj.get(Child, '-')).toEqual('-'); - }))); + expect(pmInj.get(Parent, '-')).toEqual('-'); + expect(cmInj.get(Parent, '-')).toEqual('-'); + expect(pmInj.get(Child, '-')).toEqual('-'); + expect(cmInj.get(Child, '-')).toEqual('-'); + }))); // https://github.com/angular/angular/issues/12889 it('should create a single instance of lazy-loaded modules', @@ -3689,57 +3688,55 @@ describe('Integration', () => { }))); // https://github.com/angular/angular/issues/13870 - fixmeIvy( - 'FW-767: Lazy loaded modules are not used when resolving dependencies in one of their components') - .it('should create a single instance of guards for lazy-loaded modules', - fakeAsync(inject( - [Router, Location, NgModuleFactoryLoader], - (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Injectable() - class Service { - } + it('should create a single instance of guards for lazy-loaded modules', + fakeAsync(inject( + [Router, Location, NgModuleFactoryLoader], + (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { + @Injectable() + class Service { + } - @Injectable() - class Resolver implements Resolve { - constructor(public service: Service) {} - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { - return this.service; - } - } + @Injectable() + class Resolver implements Resolve { + constructor(public service: Service) {} + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + return this.service; + } + } - @Component({selector: 'lazy', template: 'lazy'}) - class LazyLoadedComponent { - resolvedService: Service; - constructor(public injectedService: Service, route: ActivatedRoute) { - this.resolvedService = route.snapshot.data['service']; - } - } + @Component({selector: 'lazy', template: 'lazy'}) + class LazyLoadedComponent { + resolvedService: Service; + constructor(public injectedService: Service, route: ActivatedRoute) { + this.resolvedService = route.snapshot.data['service']; + } + } - @NgModule({ - declarations: [LazyLoadedComponent], - providers: [Service, Resolver], - imports: [ - RouterModule.forChild([{ - path: 'loaded', - component: LazyLoadedComponent, - resolve: {'service': Resolver}, - }]), - ] - }) - class LoadedModule { - } + @NgModule({ + declarations: [LazyLoadedComponent], + providers: [Service, Resolver], + imports: [ + RouterModule.forChild([{ + path: 'loaded', + component: LazyLoadedComponent, + resolve: {'service': Resolver}, + }]), + ] + }) + class LoadedModule { + } - loader.stubbedModules = {expected: LoadedModule}; - const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); - router.navigateByUrl('/lazy/loaded'); - advance(fixture); + loader.stubbedModules = {expected: LoadedModule}; + const fixture = createRoot(router, RootCmp); + router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); + router.navigateByUrl('/lazy/loaded'); + advance(fixture); - expect(fixture.nativeElement).toHaveText('lazy'); - const lzc = fixture.debugElement.query(By.directive(LazyLoadedComponent)) - .componentInstance; - expect(lzc.injectedService).toBe(lzc.resolvedService); - }))); + expect(fixture.nativeElement).toHaveText('lazy'); + const lzc = + fixture.debugElement.query(By.directive(LazyLoadedComponent)).componentInstance; + expect(lzc.injectedService).toBe(lzc.resolvedService); + }))); it('should emit RouteConfigLoadStart and RouteConfigLoadEnd event when route is lazy loaded', @@ -3990,28 +3987,26 @@ describe('Integration', () => { }); }); - fixmeIvy( - 'FW-767: Lazy loaded modules are not used when resolving dependencies in one of their components') - .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}; + 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); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{ - path: 'eager-parent', - component: EagerParentComponent, - children: [{path: 'lazy', loadChildren: 'expected'}] - }]); + router.resetConfig([{ + path: 'eager-parent', + component: EagerParentComponent, + children: [{path: 'lazy', loadChildren: 'expected'}] + }]); - router.navigateByUrl('/eager-parent/lazy/lazy-parent/lazy-child'); - advance(fixture); + 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'); - }))); + 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', diff --git a/packages/router/test/router_preloader.spec.ts b/packages/router/test/router_preloader.spec.ts index 4b0fabc2cc..fba50d3cac 100644 --- a/packages/router/test/router_preloader.spec.ts +++ b/packages/router/test/router_preloader.spec.ts @@ -8,7 +8,6 @@ import {Compiler, Component, NgModule, NgModuleFactoryLoader, NgModuleRef} from '@angular/core'; import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; -import {fixmeIvy} from '@angular/private/testing'; import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '@angular/router'; import {Route, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouterModule} from '../index'; @@ -60,66 +59,63 @@ describe('RouterPreloader', () => { }); }); + it('should work', + fakeAsync(inject( + [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef], + (loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router, + testModule: NgModuleRef) => { + const events: Array = []; + @NgModule({ + declarations: [LazyLoadedCmp], + imports: + [RouterModule.forChild([{path: 'LoadedModule2', component: LazyLoadedCmp}])] + }) + class LoadedModule2 { + } - fixmeIvy( - 'FW-765: NgModuleRef hierarchy is differently constructed when the router preloads modules') - .it('should work', - fakeAsync(inject( - [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef], - (loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router, - testModule: NgModuleRef) => { - const events: Array = []; - @NgModule({ - declarations: [LazyLoadedCmp], - imports: [RouterModule.forChild( - [{path: 'LoadedModule2', component: LazyLoadedCmp}])] - }) - class LoadedModule2 { - } + @NgModule({ + imports: + [RouterModule.forChild([{path: 'LoadedModule1', loadChildren: 'expected2'}])] + }) + class LoadedModule1 { + } - @NgModule({ - imports: [RouterModule.forChild( - [{path: 'LoadedModule1', loadChildren: 'expected2'}])] - }) - class LoadedModule1 { - } + router.events.subscribe(e => { + if (e instanceof RouteConfigLoadEnd || e instanceof RouteConfigLoadStart) { + events.push(e); + } + }); - router.events.subscribe(e => { - if (e instanceof RouteConfigLoadEnd || e instanceof RouteConfigLoadStart) { - events.push(e); - } - }); + loader.stubbedModules = { + expected: LoadedModule1, + expected2: LoadedModule2, + }; - loader.stubbedModules = { - expected: LoadedModule1, - expected2: LoadedModule2, - }; + preloader.preload().subscribe(() => {}); - preloader.preload().subscribe(() => {}); + tick(); - tick(); + const c = router.config; + expect(c[0].loadChildren).toEqual('expected'); - const c = router.config; - expect(c[0].loadChildren).toEqual('expected'); + const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !; + const module: any = loadedConfig.module; + expect(loadedConfig.routes[0].path).toEqual('LoadedModule1'); + expect(module._parent).toBe(testModule); - const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !; - const module: any = loadedConfig.module; - expect(loadedConfig.routes[0].path).toEqual('LoadedModule1'); - expect(module._parent).toBe(testModule); + const loadedConfig2: LoadedRouterConfig = + (loadedConfig.routes[0] as any)._loadedConfig !; + const module2: any = loadedConfig2.module; + expect(loadedConfig2.routes[0].path).toEqual('LoadedModule2'); + expect(module2._parent).toBe(module); - const loadedConfig2: LoadedRouterConfig = - (loadedConfig.routes[0] as any)._loadedConfig !; - const module2: any = loadedConfig2.module; - expect(loadedConfig2.routes[0].path).toEqual('LoadedModule2'); - expect(module2._parent).toBe(module); - - expect(events.map(e => e.toString())).toEqual([ - 'RouteConfigLoadStart(path: lazy)', - 'RouteConfigLoadEnd(path: lazy)', - 'RouteConfigLoadStart(path: LoadedModule1)', - 'RouteConfigLoadEnd(path: LoadedModule1)', - ]); - }))); + expect(events.map(e => e.toString())).toEqual([ + 'RouteConfigLoadStart(path: lazy)', + 'RouteConfigLoadEnd(path: lazy)', + 'RouteConfigLoadStart(path: LoadedModule1)', + 'RouteConfigLoadEnd(path: LoadedModule1)', + ]); + }))); }); describe('should support modules that have already been loaded', () => { @@ -130,60 +126,57 @@ describe('RouterPreloader', () => { }); }); - fixmeIvy( - 'FW-765: NgModuleRef hierarchy is differently constructed when the router preloads modules') - .it('should work', - fakeAsync(inject( - [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler], - (loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router, - testModule: NgModuleRef, compiler: Compiler) => { - @NgModule() - class LoadedModule2 { - } + it('should work', fakeAsync(inject( + [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler], + (loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, + router: Router, testModule: NgModuleRef, compiler: Compiler) => { + @NgModule() + class LoadedModule2 { + } - const module2 = compiler.compileModuleSync(LoadedModule2).create(null); + const module2 = compiler.compileModuleSync(LoadedModule2).create(null); - @NgModule({ - imports: [RouterModule.forChild([ - { - path: 'LoadedModule2', - loadChildren: 'no', - _loadedConfig: { - routes: [{path: 'LoadedModule3', loadChildren: 'expected3'}], - module: module2, - } - }, - ])] - }) - class LoadedModule1 { - } + @NgModule({ + imports: [RouterModule.forChild([ + { + path: 'LoadedModule2', + loadChildren: 'no', + _loadedConfig: { + routes: [{path: 'LoadedModule3', loadChildren: 'expected3'}], + module: module2, + } + }, + ])] + }) + class LoadedModule1 { + } - @NgModule({imports: [RouterModule.forChild([])]}) - class LoadedModule3 { - } + @NgModule({imports: [RouterModule.forChild([])]}) + class LoadedModule3 { + } - loader.stubbedModules = { - expected: LoadedModule1, - expected3: LoadedModule3, - }; + loader.stubbedModules = { + expected: LoadedModule1, + expected3: LoadedModule3, + }; - preloader.preload().subscribe(() => {}); + preloader.preload().subscribe(() => {}); - tick(); + tick(); - const c = router.config; + const c = router.config; - const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !; - const module: any = loadedConfig.module; - expect(module._parent).toBe(testModule); + const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !; + const module: any = loadedConfig.module; + expect(module._parent).toBe(testModule); - const loadedConfig2: LoadedRouterConfig = - (loadedConfig.routes[0] as any)._loadedConfig !; - const loadedConfig3: LoadedRouterConfig = - (loadedConfig2.routes[0] as any)._loadedConfig !; - const module3: any = loadedConfig3.module; - expect(module3._parent).toBe(module2); - }))); + const loadedConfig2: LoadedRouterConfig = + (loadedConfig.routes[0] as any)._loadedConfig !; + const loadedConfig3: LoadedRouterConfig = + (loadedConfig2.routes[0] as any)._loadedConfig !; + const module3: any = loadedConfig3.module; + expect(module3._parent).toBe(module2); + }))); }); describe('should ignore errors', () => {