fix(ivy): componentFactories not populated in ModuleWithComponentFactories (#28112)

Fixes the `ModuleWithComponentFactories.componentFactories` not being populated when calling `compileModuleAndAllComponentsSync` in Ivy.

These changes resolve FW-929.

PR Close #28112
This commit is contained in:
Kristiyan Kostadinov 2019-01-13 13:55:15 +01:00 committed by Andrew Kushnir
parent da1d19b40f
commit bac71ef419
3 changed files with 57 additions and 36 deletions

View File

@ -12,6 +12,8 @@ import {StaticProvider} from '../di/interface/provider';
import {MissingTranslationStrategy} from '../i18n/tokens';
import {Type} from '../interface/type';
import {ViewEncapsulation} from '../metadata';
import {ComponentFactory as ComponentFactoryR3} from '../render3/component_ref';
import {getComponentDef, getNgModuleDef} from '../render3/definition';
import {NgModuleFactory as NgModuleFactoryR3} from '../render3/ng_module_ref';
import {ComponentFactory} from './component_factory';
@ -56,7 +58,14 @@ const Compiler_compileModuleAndAllComponentsSync__PRE_R3__: <T>(moduleType: Type
export const Compiler_compileModuleAndAllComponentsSync__POST_R3__: <T>(moduleType: Type<T>) =>
ModuleWithComponentFactories<T> = function<T>(moduleType: Type<T>):
ModuleWithComponentFactories<T> {
return new ModuleWithComponentFactories(Compiler_compileModuleSync__POST_R3__(moduleType), []);
const ngModuleFactory = Compiler_compileModuleSync__POST_R3__(moduleType);
const moduleDef = getNgModuleDef(moduleType) !;
const componentFactories = moduleDef.declarations.reduce((factories, declaration) => {
const componentDef = getComponentDef(declaration);
componentDef && factories.push(new ComponentFactoryR3(componentDef));
return factories;
}, [] as ComponentFactory<any>[]);
return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
};
const Compiler_compileModuleAndAllComponentsSync =
Compiler_compileModuleAndAllComponentsSync__PRE_R3__;

View File

@ -1097,45 +1097,44 @@ function declareTests(config?: {useJit: boolean}) {
.toHaveText('dynamic greet');
}));
fixmeIvy('FW-929: ModuleWithComponentFactories.componentFactories is never filled in')
.it('should create a component that has been freshly compiled', () => {
@Component({template: ''})
class RootComp {
constructor(public vc: ViewContainerRef) {}
}
it('should create a component that has been freshly compiled', () => {
@Component({template: ''})
class RootComp {
constructor(public vc: ViewContainerRef) {}
}
@NgModule({
declarations: [RootComp],
providers: [{provide: 'someToken', useValue: 'someRootValue'}],
})
class RootModule {
}
@NgModule({
declarations: [RootComp],
providers: [{provide: 'someToken', useValue: 'someRootValue'}],
})
class RootModule {
}
@Component({template: ''})
class MyComp {
constructor(@Inject('someToken') public someToken: string) {}
}
@Component({template: ''})
class MyComp {
constructor(@Inject('someToken') public someToken: string) {}
}
@NgModule({
declarations: [MyComp],
providers: [{provide: 'someToken', useValue: 'someValue'}],
})
class MyModule {
}
@NgModule({
declarations: [MyComp],
providers: [{provide: 'someToken', useValue: 'someValue'}],
})
class MyModule {
}
const compFixture = TestBed.configureTestingModule({imports: [RootModule]})
.createComponent(RootComp);
const compiler = <Compiler>TestBed.get(Compiler);
const myCompFactory =
<ComponentFactory<MyComp>>compiler.compileModuleAndAllComponentsSync(MyModule)
.componentFactories[0];
const compFixture =
TestBed.configureTestingModule({imports: [RootModule]}).createComponent(RootComp);
const compiler = <Compiler>TestBed.get(Compiler);
const myCompFactory =
<ComponentFactory<MyComp>>compiler.compileModuleAndAllComponentsSync(MyModule)
.componentFactories[0];
// Note: the ComponentFactory was created directly via the compiler, i.e. it
// does not have an association to an NgModuleRef.
// -> expect the providers of the module that the view container belongs to.
const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory);
expect(compRef.instance.someToken).toBe('someRootValue');
});
// Note: the ComponentFactory was created directly via the compiler, i.e. it
// does not have an association to an NgModuleRef.
// -> expect the providers of the module that the view container belongs to.
const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory);
expect(compRef.instance.someToken).toBe('someRootValue');
});
it('should create a component with the passed NgModuleRef', () => {
@Component({template: ''})

View File

@ -700,6 +700,17 @@ export class TestBedRender3 implements Injector, TestBed {
});
}
/**
* @internal
*/
_getComponentFactories(moduleType: NgModuleType): ComponentFactory<any>[] {
return moduleType.ngModuleDef.declarations.reduce((factories, declaration) => {
const componentDef = (declaration as any).ngComponentDef;
componentDef && factories.push(new ComponentFactory(componentDef, this._moduleRef));
return factories;
}, [] as ComponentFactory<any>[]);
}
/**
* Check whether the module scoping queue should be flushed, and flush it if needed.
*
@ -757,7 +768,9 @@ class R3TestCompiler implements Compiler {
}
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> {
return new ModuleWithComponentFactories(this.compileModuleSync(moduleType), []);
const ngModuleFactory = this.compileModuleSync(moduleType);
const componentFactories = this.testBed._getComponentFactories(moduleType as NgModuleType<T>);
return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
}
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>):