On the Chakra backend, throwing a Napi::TypeError (or any Napi::Error) from a class constructor body — i.e. inside the function passed to Napi::ObjectWrap<T> / napi_define_class's callback — does not surface as a catchable JS exception. Instead the JS-side new MyClass() resolves to a half-constructed instance, so test code like expect(() => new (File as any)()).to.throw() silently fails.
This forces polyfills with required constructor arguments (WHATWG File, future Request, etc.) to either skip the WebIDL "missing required argument → TypeError" surface on Chakra, or omit the corresponding tests on Chakra.
Repro
class Foo : public Napi::ObjectWrap<Foo> {
public:
static Napi::Function Init(Napi::Env env) {
return DefineClass(env, "Foo", {});
}
Foo(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Foo>(info) {
throw Napi::TypeError::New(info.Env(), "always throws");
}
};
In JS on Chakra: expect(() => new Foo()).to.throw() fails — no exception is thrown.
On V8 and JSC: throws as expected.
Current workaround
In Polyfills/File/Tests/UnitTests/Scripts/tests.ts (introduced by #169), tests that assert the constructor throws on missing/invalid arguments are commented out with a TODO pointing here. They should be re-enabled atomically when this is fixed.
Likely root cause
The Chakra napi shim's ExternalCallback::Callback (in Core/Node-API/Source/js_native_api_chakra.cc) probably needs to translate env->last_exception into a JsRT exception via JsSetException before returning to the JsRT runtime when invoked in construct mode. The function-call path likely already does this; the constructor path appears not to.
Related
- JsRH#172 (separate JSC napi shim quirk).
- JsRH#169 (the PR that surfaced this).
On the Chakra backend, throwing a
Napi::TypeError(or any Napi::Error) from a class constructor body — i.e. inside the function passed toNapi::ObjectWrap<T>/napi_define_class's callback — does not surface as a catchable JS exception. Instead the JS-sidenew MyClass()resolves to a half-constructed instance, so test code likeexpect(() => new (File as any)()).to.throw()silently fails.This forces polyfills with required constructor arguments (WHATWG
File, futureRequest, etc.) to either skip the WebIDL "missing required argument → TypeError" surface on Chakra, or omit the corresponding tests on Chakra.Repro
In JS on Chakra:
expect(() => new Foo()).to.throw()fails — no exception is thrown.On V8 and JSC: throws as expected.
Current workaround
In
Polyfills/File/Tests/UnitTests/Scripts/tests.ts(introduced by #169), tests that assert the constructor throws on missing/invalid arguments are commented out with a TODO pointing here. They should be re-enabled atomically when this is fixed.Likely root cause
The Chakra napi shim's
ExternalCallback::Callback(inCore/Node-API/Source/js_native_api_chakra.cc) probably needs to translateenv->last_exceptioninto a JsRT exception viaJsSetExceptionbefore returning to the JsRT runtime when invoked in construct mode. The function-call path likely already does this; the constructor path appears not to.Related