feat(ivy): implement a Compiler for use in TestBedRender3 (#28033)
Previously when testing code injected the Compiler, it received the top-level Compiler implementation defined in linker/compiler.ts (and governed by the __PRE_R3__ switch). Code running under the TestBed, however, should always use a TestBed-aware Compiler implementation. This commit adds such an implementation to the TestBedRender3, which passes compiled modules through the _compileNgModule() function. With this change, 3 formerly disabled router integration tests now pass. FW-855 #resolve PR Close #28033
This commit is contained in:
parent
94893accdb
commit
51e716b6f2
|
@ -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<T>(values: any[], mapFn?: (value: T) => any): T[] {
|
|||
function isNgModule<T>(value: Type<T>): value is Type<T>&{ngModuleDef: NgModuleDef<T>} {
|
||||
return (value as{ngModuleDef?: NgModuleDef<T>}).ngModuleDef !== undefined;
|
||||
}
|
||||
|
||||
class R3TestCompiler implements Compiler {
|
||||
constructor(private testBed: TestBedRender3) {}
|
||||
|
||||
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> {
|
||||
this.testBed._compileNgModule(moduleType as NgModuleType<T>);
|
||||
return new R3NgModuleFactory(moduleType);
|
||||
}
|
||||
|
||||
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> {
|
||||
return Promise.resolve(this.compileModuleSync(moduleType));
|
||||
}
|
||||
|
||||
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> {
|
||||
return new ModuleWithComponentFactories(this.compileModuleSync(moduleType), []);
|
||||
}
|
||||
|
||||
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>):
|
||||
Promise<ModuleWithComponentFactories<T>> {
|
||||
return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType));
|
||||
}
|
||||
|
||||
clearCache(): void {}
|
||||
|
||||
clearCacheFor(type: Type<any>): void {}
|
||||
|
||||
getModuleId(moduleType: Type<any>): string|undefined { return undefined; }
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
})));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue