diff --git a/packages/core/testing/src/r3_test_bed.ts b/packages/core/testing/src/r3_test_bed.ts index fbbf9e583c..6e558f7853 100644 --- a/packages/core/testing/src/r3_test_bed.ts +++ b/packages/core/testing/src/r3_test_bed.ts @@ -6,7 +6,48 @@ * found in the LICENSE file at https://angular.io/license */ -import {ApplicationInitStatus, Component, Directive, Injector, NgModule, NgZone, Pipe, PlatformRef, Provider, SchemaMetadata, Type, resolveForwardRef, ɵInjectableDef as InjectableDef, ɵNG_COMPONENT_DEF as NG_COMPONENT_DEF, ɵNG_DIRECTIVE_DEF as NG_DIRECTIVE_DEF, ɵNG_INJECTOR_DEF as NG_INJECTOR_DEF, ɵNG_MODULE_DEF as NG_MODULE_DEF, ɵNG_PIPE_DEF as NG_PIPE_DEF, ɵNgModuleDef as NgModuleDef, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵNgModuleType as NgModuleType, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵresetCompiledComponents as resetCompiledComponents, ɵstringify as stringify, ɵtransitiveScopesFor as transitiveScopesFor} from '@angular/core'; +// The formatter and CI disagree on how this import statement should be formatted. Both try to keep +// it on one line, too, which has gotten very hard to read & manage. So disable the formatter for +// this statement only. +// clang-format off +import { + ApplicationInitStatus, + Compiler, + Component, + Directive, + Injector, + ModuleWithComponentFactories, + NgModule, + NgModuleFactory, + NgZone, + Pipe, + PlatformRef, + Provider, + SchemaMetadata, + Type, + resolveForwardRef, + ɵInjectableDef as InjectableDef, + ɵNG_COMPONENT_DEF as NG_COMPONENT_DEF, + ɵNG_DIRECTIVE_DEF as NG_DIRECTIVE_DEF, + ɵNG_INJECTOR_DEF as NG_INJECTOR_DEF, + ɵNG_MODULE_DEF as NG_MODULE_DEF, + ɵNG_PIPE_DEF as NG_PIPE_DEF, + ɵNgModuleDef as NgModuleDef, + ɵNgModuleFactory as R3NgModuleFactory, + ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, + ɵNgModuleType as NgModuleType, + ɵRender3ComponentFactory as ComponentFactory, + ɵRender3NgModuleRef as NgModuleRef, + ɵcompileComponent as compileComponent, + ɵcompileDirective as compileDirective, + ɵcompileNgModuleDefs as compileNgModuleDefs, + ɵcompilePipe as compilePipe, + ɵgetInjectableDef as getInjectableDef, + ɵpatchComponentDefWithScope as patchComponentDefWithScope, + ɵresetCompiledComponents as resetCompiledComponents, + ɵstringify as stringify, ɵtransitiveScopesFor as transitiveScopesFor, +} from '@angular/core'; +// clang-format on import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; @@ -486,8 +527,12 @@ export class TestBedRender3 implements Injector, TestBed { } const ngZone = new NgZone({enableLongStackTrace: true}); - const providers = - [{provide: NgZone, useValue: ngZone}, ...this._providers, ...this._providerOverrides]; + const providers = [ + {provide: NgZone, useValue: ngZone}, + {provide: Compiler, useFactory: () => new R3TestCompiler(this)}, + ...this._providers, + ...this._providerOverrides, + ]; const declarations = this._declarations; const imports = [RootScopeModule, this.ngModule, this._imports]; @@ -521,7 +566,10 @@ export class TestBedRender3 implements Injector, TestBed { return Object.keys(overrides).length ? {...meta, ...overrides} : meta; } - private _compileNgModule(moduleType: NgModuleType): void { + /** + * @internal + */ + _compileNgModule(moduleType: NgModuleType): void { const ngModule = this._resolvers.module.resolve(moduleType); if (ngModule === null) { @@ -614,3 +662,31 @@ function flatten(values: any[], mapFn?: (value: T) => any): T[] { function isNgModule(value: Type): value is Type&{ngModuleDef: NgModuleDef} { return (value as{ngModuleDef?: NgModuleDef}).ngModuleDef !== undefined; } + +class R3TestCompiler implements Compiler { + constructor(private testBed: TestBedRender3) {} + + compileModuleSync(moduleType: Type): NgModuleFactory { + this.testBed._compileNgModule(moduleType as NgModuleType); + return new R3NgModuleFactory(moduleType); + } + + compileModuleAsync(moduleType: Type): Promise> { + return Promise.resolve(this.compileModuleSync(moduleType)); + } + + compileModuleAndAllComponentsSync(moduleType: Type): ModuleWithComponentFactories { + return new ModuleWithComponentFactories(this.compileModuleSync(moduleType), []); + } + + compileModuleAndAllComponentsAsync(moduleType: Type): + Promise> { + return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType)); + } + + clearCache(): void {} + + clearCacheFor(type: Type): void {} + + getModuleId(moduleType: Type): string|undefined { return undefined; } +} diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 74ce8e7d4a..5edb0bc5be 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -4024,27 +4024,26 @@ describe('Integration', () => { }); }); - fixmeIvy('FW-887: JIT: compilation of NgModule') - .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', @@ -4367,43 +4366,41 @@ describe('Integration', () => { class LazyLoadedModule { } - fixmeIvy('FW-887: JIT: compilation of NgModule') - .it('should not ignore empty path when in legacy mode', - fakeAsync(inject( - [Router, NgModuleFactoryLoader], - (router: Router, loader: SpyNgModuleFactoryLoader) => { - router.relativeLinkResolution = 'legacy'; - loader.stubbedModules = {expected: LazyLoadedModule}; + it('should not ignore empty path when in legacy mode', + fakeAsync(inject( + [Router, NgModuleFactoryLoader], + (router: Router, loader: SpyNgModuleFactoryLoader) => { + router.relativeLinkResolution = 'legacy'; + loader.stubbedModules = {expected: LazyLoadedModule}; - const fixture = createRoot(router, RootCmp); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); + router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); - router.navigateByUrl('/lazy/foo/bar'); - advance(fixture); + router.navigateByUrl('/lazy/foo/bar'); + advance(fixture); - const link = fixture.nativeElement.querySelector('a'); - expect(link.getAttribute('href')).toEqual('/lazy/foo/bar/simple'); - }))); + const link = fixture.nativeElement.querySelector('a'); + expect(link.getAttribute('href')).toEqual('/lazy/foo/bar/simple'); + }))); - fixmeIvy('FW-887: JIT: compilation of NgModule') - .it('should ignore empty path when in corrected mode', - fakeAsync(inject( - [Router, NgModuleFactoryLoader], - (router: Router, loader: SpyNgModuleFactoryLoader) => { - router.relativeLinkResolution = 'corrected'; - loader.stubbedModules = {expected: LazyLoadedModule}; + it('should ignore empty path when in corrected mode', + fakeAsync(inject( + [Router, NgModuleFactoryLoader], + (router: Router, loader: SpyNgModuleFactoryLoader) => { + router.relativeLinkResolution = 'corrected'; + loader.stubbedModules = {expected: LazyLoadedModule}; - const fixture = createRoot(router, RootCmp); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); + router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); - router.navigateByUrl('/lazy/foo/bar'); - advance(fixture); + router.navigateByUrl('/lazy/foo/bar'); + advance(fixture); - const link = fixture.nativeElement.querySelector('a'); - expect(link.getAttribute('href')).toEqual('/lazy/foo/simple'); - }))); + const link = fixture.nativeElement.querySelector('a'); + expect(link.getAttribute('href')).toEqual('/lazy/foo/simple'); + }))); }); });