-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Description
Which @angular/* package(s) are relevant/related to the feature request?
core
Description
TL;DR: TestBed should provide a way to run zoneless and avoid importing zone.js when we don't need it.
And I'd love to help with a PR?
TestBed assumes that zone.js is available while there are contexts when this is not necessary and here are some examples:
- zoneless apps & libs
- tests that do not depend on change detection: service tests, pipe tests, "isolated" component testing etc...
- tests where CD is triggered manually using
fixture.detectChanges()
These tests must load zone.js when they don't need it.
While this might sound like a really minor issue, loading zone.js can cause trouble in some situations.
For instance, integrating TestBed and zone.js with vitest causes the following error Method Promise.prototype.then called on incompatible receiver which is probably due to zone.js patching promises and breaking Node.js's safe promises when importing ESMs dynamically or something like that. This is similar to the issue described here #47872.
Proposed solution
A first quick win is replacing this:
angular/packages/core/testing/src/test_bed_compiler.ts
Lines 749 to 751 in 6948f0f
| const ngZone = new NgZone({enableLongStackTrace: true}); | |
| const providers: Provider[] = [ | |
| {provide: NgZone, useValue: ngZone}, |
with:
{provide: NgZone, useFactory: () => new NgZone({enableLongStackTrace: true}); }this would then allow us to go zoneless with this configuration:
TestBed.configureTestingModule({
providers: [
{
provide: NgZone,
useClass: ɵNoopNgZone,
},
],
});The main problem with this approach is the boilerplate and having to use the ɵNoopNgZone implementation detail.
A second step would be adding the bootstrap's ngZone option to initTestEnvironment:
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
{ngZone: 'noop'}
);Alternatives considered
Disable promises monkey patching using globalThis.__Zone_disable_ZoneAwarePromise = true
but this causes the following issue #37349
Cf. #48359