Skip to content

Zone.js Promise monkey patching issue with Node.js dynamic import #48359

@yjaaidi

Description

@yjaaidi

Which @angular/* package(s) are the source of the bug?

zone.js

Is this a regression?

No

Description

I am working on Angular compatibility with Vitest and I encountered an issue with Zone.js.

I get the following error:

Method Promise.prototype.then called on incompatible receiver

which looks similar to this old issue #32802.
IMO, there is an issue with Vitest which is using Node.js ESM & dynamic import but the Promise is monkey patched by Zone.js.

I tried disabling Promise monkey patching using globalThis.__Zone_disable_ZoneAwarePromise = true;

Then I get the following error in @angular/core/testing:

Error: Expected to be running in 'ProxyZone', but it was not found.
 ❯ Function.ProxyZoneSpec.assertPresent node_modules/zone.js/bundles/zone-testing.umd.js:217:23
 ❯ Object.resetFakeAsyncZone node_modules/zone.js/bundles/zone-testing.umd.js:2061:54
 ❯ resetFakeAsyncZone ../../packages/core/testing/src/fake_async.ts:23:32

If I manually change the zone.js source code and remove this assertion, the next error is:

Error: Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.
Most likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)
 ❯ Function.Zone.assertZonePatched node_modules/zone.js/bundles/zone.umd.js:72:27
 ❯ new NgZone ../../packages/core/src/zone/ng_zone.ts:136:10
 ❯ TestBedCompiler.compileTestModule ../../packages/core/testing/src/test_bed_compiler.ts:749:20
 ❯ TestBedCompiler.finalize ../../packages/core/testing/src/test_bed_compiler.ts:275:10
 ❯ TestBedImpl.get testModuleRef [as testModuleRef] ../../packages/core/testing/src/test_bed.ts:615:43
 ❯ TestBedImpl.inject ../../packages/core/testing/src/test_bed.ts:504:25
 ❯ inject ../../packages/core/testing/src/test_bed.ts:314:33

Is there a way to monkey patch promises without breaking Node.js dynamic import?

If this isn't possible, then we should fix __Zone_disable_ZoneAwarePromise.
Maybe:

  1. by making sure that ProxyZoneSpec.assertPresent() doesn't fail
  2. by adding a !global['__Zone_disable_ZoneAwarePromise'] precondition in assertZonePatched

What do you think?

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 15.0.2
Node: 18.12.1
Package Manager: npm 8.19.2
OS: darwin x64

Angular: 15.0.2
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1500.2
@angular-devkit/build-angular   15.0.2
@angular-devkit/core            15.0.2
@angular-devkit/schematics      15.0.2
@angular/cdk                    15.0.1
@angular/material               15.0.1
@schematics/angular             15.0.2
rxjs                            7.5.6
typescript                      4.8.4

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions