diff --git a/src/modules/events.c b/src/modules/events.c index 65cc68a..d08284c 100644 --- a/src/modules/events.c +++ b/src/modules/events.c @@ -1129,6 +1129,15 @@ static void js_events_once_remove_listener_from_target(ant_t *js, ant_value_t st return; } + if (is_eventtarget_instance(target)) { + ant_value_t remove_method = js_getprop_fallback(js, target, "removeEventListener"); + if (!is_callable(remove_method)) return; + + ant_value_t call_args[2] = { key, listener }; + eventemitter_call_listener(js, remove_method, target, call_args, 2); + return; + } + ant_value_t remove_method = js_getprop_fallback(js, target, "removeListener"); if (!is_callable(remove_method)) return; diff --git a/tests/test_node_events_once_eventtarget_abort.cjs b/tests/test_node_events_once_eventtarget_abort.cjs new file mode 100644 index 0000000..e878499 --- /dev/null +++ b/tests/test_node_events_once_eventtarget_abort.cjs @@ -0,0 +1,33 @@ +const assert = require('node:assert'); +const events = require('node:events'); + +class ObservedEventTarget extends EventTarget { + constructor() { + super(); + this.removedReady = false; + } + + removeEventListener(type, listener, options) { + if (type === 'ready' && typeof listener === 'function') { + this.removedReady = true; + } + return super.removeEventListener(type, listener, options); + } +} + +(async () => { + const target = new ObservedEventTarget(); + const controller = new AbortController(); + const promise = events.once(target, 'ready', { signal: controller.signal }); + + controller.abort(); + + await assert.rejects(promise); + assert.strictEqual(target.removedReady, true); + + console.log('node-events-once-eventtarget-abort:ok'); +})().catch((err) => { + setTimeout(() => { + throw err; + }); +});