TestBed overridden providers always registered in NgModule injector
🐞 bug report
Affected Package
The issue is caused by package @angular/core/testing
Is this a regression?
Sort of; changed behavior in Ivy compared to VE.
Description
In #28737 the following testcase was added to exercise ngOnDestroy logic registered for component-level provided providers that have been overridden:
it('should call ngOnDestroy for a service that was overridden with useFactory', () => {
const logs: string[] = [];
@Injectable()
class MyService {
public name = 'MyService';
ngOnDestroy() {
logs.push('MyService.ngOnDestroy');
}
}
class FakeService {
name = 'FakeService';
ngOnDestroy() {
logs.push('FakeService.ngOnDestroy');
}
}
@Component({
selector: 'my-comp',
template: `{{ myService.name }}`,
providers: [MyService],
})
class MyComponent {
constructor(public myService: MyService) {}
}
TestBed.configureTestingModule({
declarations: [MyComponent],
});
TestBed.overrideProvider(MyService, {
useFactory: () => new FakeService(),
});
const fixture = TestBed.createComponent(MyComponent);
fixture.detectChanges();
const service = TestBed.inject(MyService);
expect(service.name).toBe('FakeService');
fixture.destroy();
expect(logs).toEqual(['FakeService.ngOnDestroy']);
});
In this test, the MyService token is provided by the component and overridden using TestBed.overriddeProvider. In Ivy, the TestBed.inject(MyService); call succeeds and returns an instance of FakeService. In VE, this call fails as there is no MyService token registered in the NgModule injector.
The VE behavior seems logical to me, as the service wasn't originally provided in the NgModule injector and only registering an override should not register it at the NgModule level.
In Ivy, all provider overrides are registered in the NgModule injector:
https://github.com/angular/angular/blob/44bb85ade456a8223851b3b376fe7f5c8fe0864a/packages/core/testing/src/r3_test_bed_compiler.ts#L660-L665
🔬 Minimal Reproduction
See testcase above.
🌍 Your Environment
Angular Version: Latest master, 11.0.0-next.4
This issue affects at least one g3 target (I'm surprised that it's just one), more info in cl/351872802.
The workaround for this issue is to move the component level providers into the associated NgModule.