angular / angular/angular

TestBed overridden providers always registered in NgModule injector

Open
#39,080 1 comment 0 reactions 1 assignee Claimed by @AndrewKushnir View on GitHub
area: testing core: di hotlist: google P3
Dominant language
TypeScript
Stars
101k
Forks
27.5k
Avg merge
1d 19h
Merged PRs (30d)
288

Description

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

```ts
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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.