Skip to content

TestBed overridden providers always registered in NgModule injector #39080

@JoostK

Description

@JoostK

🐞 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:

const providers: Provider[] = [
{provide: NgZone, useValue: ngZone},
{provide: Compiler, useFactory: () => new R3TestCompiler(this)},
...this.providers,
...this.providerOverrides,
];

🔬 Minimal Reproduction

See testcase above.

🌍 Your Environment

Angular Version:
Latest master, 11.0.0-next.4

Metadata

Metadata

Assignees

Labels

P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: testingIssues related to Angular testing features, such as TestBedcore: dihotlist: google

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions