fix(ivy): avoid using stale cache in TestBed if module overrides are defined (#33787)

NgModule compilation in JIT mode (that is also used in TestBed) caches module scopes on NgModule defs (using `transitiveCompileScopes` field). Module overrides (defined via TestBed.overrideModule) may invalidate this data by adding/removing items in `declarations` list. This commit forces TestBed to recalculate transitive scopes in case module overrides are present, so TestBed always gets the most up-to-date information.

PR Close #33787
This commit is contained in:
Andrew Kushnir
2019-11-12 23:03:46 -08:00
committed by Alex Rickabaugh
parent a09d60cb50
commit fbd2133610
3 changed files with 83 additions and 16 deletions

View File

@ -88,6 +88,7 @@ export class R3TestBedCompiler {
private testModuleType: NgModuleType<any>;
private testModuleRef: NgModuleRef<any>|null = null;
private hasModuleOverrides: boolean = false;
constructor(private platform: PlatformRef, private additionalModuleTypes: Type<any>|Type<any>[]) {
class DynamicTestModule {}
@ -122,6 +123,8 @@ export class R3TestBedCompiler {
}
overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void {
this.hasModuleOverrides = true;
// Compile the module right away.
this.resolvers.module.addOverride(ngModule, override);
const metadata = this.resolvers.module.resolve(ngModule);
@ -331,8 +334,15 @@ export class R3TestBedCompiler {
const getScopeOfModule =
(moduleType: Type<any>| TestingModuleOverride): NgModuleTransitiveScopes => {
if (!moduleToScope.has(moduleType)) {
const realType = isTestingModuleOverride(moduleType) ? this.testModuleType : moduleType;
moduleToScope.set(moduleType, transitiveScopesFor(realType));
const isTestingModule = isTestingModuleOverride(moduleType);
const realType = isTestingModule ? this.testModuleType : moduleType as Type<any>;
// Module overrides (via TestBed.overrideModule) might affect scopes that were
// previously calculated and stored in `transitiveCompileScopes`. If module overrides
// are present, always re-calculate transitive scopes to have the most up-to-date
// information available. The `moduleToScope` map avoids repeated re-calculation of
// scopes for the same module.
const forceRecalc = !isTestingModule && this.hasModuleOverrides;
moduleToScope.set(moduleType, transitiveScopesFor(realType, forceRecalc));
}
return moduleToScope.get(moduleType) !;
};