fix(core): associate the NgModule scope for an overridden component (#42817)

When using `TestBed.overrideComponent`, the overridden component would
incorrectly lose access to its NgModule's declaration scope if the
NgModule had been imported into the testing NgModule as a
`ModuleWithProviders`, e.g. using a `forRoot` call.

The issue occurred as the `TestBed` compiler did not consider NgModules
that had been imported as a `ModuleWithProviders` when associating
NgModules with component overrides. This caused the overridden component
to be compiled standalone, meaning that it does not have access to
its NgModule's declarations. This commit extends the logic for
traversing the NgModule graph to also consider `ModuleWithProviders`
imports.

Fixes #42734

PR Close #42817
This commit is contained in:
JoostK 2021-07-10 23:24:03 +02:00 committed by Andrew Kushnir
parent 51156f3f07
commit cd2d82a91a
2 changed files with 21 additions and 0 deletions

View File

@ -248,6 +248,25 @@ describe('TestBed', () => {
expect(hello.nativeElement).toHaveText('Hello World!');
});
// https://github.com/angular/angular/issues/42734
it('should override a component which is declared in an NgModule which is imported as a `ModuleWithProviders`',
() => {
// This test verifies that an overridden component that is declared in an NgModule that has
// been imported as a `ModuleWithProviders` continues to have access to the declaration scope
// of the NgModule.
TestBed.resetTestingModule();
const moduleWithProviders:
ModuleWithProviders<HelloWorldModule> = {ngModule: HelloWorldModule};
TestBed.configureTestingModule({imports: [moduleWithProviders]});
TestBed.overrideComponent(
HelloWorld, {set: {template: 'Overridden <greeting-cmp></greeting-cmp>'}});
const hello = TestBed.createComponent(HelloWorld);
hello.detectChanges();
expect(hello.nativeElement).toHaveText('Overridden Hello World!');
});
it('should run `APP_INITIALIZER` before accessing `LOCALE_ID` provider', () => {
let locale: string = '';
@NgModule({

View File

@ -538,6 +538,8 @@ export class R3TestBedCompiler {
this.queueTypeArray(maybeUnwrapFn(def.declarations), value);
queueTypesFromModulesArrayRecur(maybeUnwrapFn(def.imports));
queueTypesFromModulesArrayRecur(maybeUnwrapFn(def.exports));
} else if (isModuleWithProviders(value)) {
queueTypesFromModulesArrayRecur([value.ngModule]);
}
}
};