Repository: denoland/deno
Pull request: fix(ext/node): fix events.getEventListeners

This PR fixes events.getEventListners when the input target is an instance of EventTarget. This enables `parallel/test-events-static-geteventlisteners.js`.

towards #29595 

Changed files:
filename: ext/node/polyfills/_events.mjs
patch: @@ -844,7 +844,9 @@ export function getEventListeners(emitterOrTarget, type) {
     return emitterOrTarget.listeners(type);
   }
   if (emitterOrTarget instanceof EventTarget) {
-    return emitterOrTarget[eventTargetData]?.listeners?.[type] || [];
+    return emitterOrTarget[eventTargetData]?.listeners?.[type]?.map((
+      listener,
+    ) => listener.callback) || [];
   }
   throw new ERR_INVALID_ARG_TYPE(
     "emitter",

filename: tests/node_compat/config.jsonc
patch: @@ -542,6 +542,7 @@
       "test-events-listener-count-with-listener.js",
       "test-events-on-async-iterator.js",
       "test-events-once.js",
+      "test-events-static-geteventlisteners.js",
       "test-events-uncaught-exception-stack.js",
       "test-eventtarget-brandcheck.js",
       "test-eventtarget-once-twice.js",

filename: tests/node_compat/runner/TODO.md
patch: @@ -1,7 +1,7 @@
 <!-- deno-fmt-ignore-file -->
 # Remaining Node Tests
 
-1202 tests out of 3993 have been ported from Node 23.9.0 (30.10% ported, 70.50% remaining).
+1203 tests out of 3993 have been ported from Node 23.9.0 (30.13% ported, 70.47% remaining).
 
 NOTE: This file should not be manually edited. Please edit `tests/node_compat/config.json` and run `deno task setup` in `tests/node_compat/runner` dir instead.
 
@@ -743,7 +743,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
 - [parallel/test-esm-loader-hooks-inspect-wait.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-esm-loader-hooks-inspect-wait.js)
 - [parallel/test-eval-disallow-code-generation-from-strings.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-eval-disallow-code-generation-from-strings.js)
 - [parallel/test-eventemitter-asyncresource.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-eventemitter-asyncresource.js)
-- [parallel/test-events-static-geteventlisteners.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-events-static-geteventlisteners.js)
 - [parallel/test-eventsource-disabled.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-eventsource-disabled.js)
 - [parallel/test-eventsource.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-eventsource.js)
 - [parallel/test-eventtarget-memoryleakwarning.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-eventtarget-memoryleakwarning.js)

filename: tests/node_compat/test/parallel/test-events-static-geteventlisteners.js
patch: @@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 23.9.0
+// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Flags: --expose-internals --no-warnings
+const common = require('../common');
+const { kWeakHandler } = require('internal/event_target');
+
+const {
+  deepStrictEqual,
+  throws,
+} = require('assert');
+
+const { getEventListeners, EventEmitter } = require('events');
+
+// Test getEventListeners on EventEmitter
+{
+  const fn1 = common.mustNotCall();
+  const fn2 = common.mustNotCall();
+  const emitter = new EventEmitter();
+  emitter.on('foo', fn1);
+  emitter.on('foo', fn2);
+  emitter.on('baz', fn1);
+  emitter.on('baz', fn1);
+  deepStrictEqual(getEventListeners(emitter, 'foo'), [fn1, fn2]);
+  deepStrictEqual(getEventListeners(emitter, 'bar'), []);
+  deepStrictEqual(getEventListeners(emitter, 'baz'), [fn1, fn1]);
+}
+// Test getEventListeners on EventTarget
+{
+  const fn1 = common.mustNotCall();
+  const fn2 = common.mustNotCall();
+  const target = new EventTarget();
+  target.addEventListener('foo', fn1);
+  target.addEventListener('foo', fn2);
+  target.addEventListener('baz', fn1);
+  target.addEventListener('baz', fn1);
+  deepStrictEqual(getEventListeners(target, 'foo'), [fn1, fn2]);
+  deepStrictEqual(getEventListeners(target, 'bar'), []);
+  deepStrictEqual(getEventListeners(target, 'baz'), [fn1]);
+}
+
+{
+  throws(() => {
+    getEventListeners('INVALID_EMITTER');
+  }, /ERR_INVALID_ARG_TYPE/);
+}
+{
+  // Test weak listeners
+  const target = new EventTarget();
+  const fn = common.mustNotCall();
+  target.addEventListener('foo', fn, { [kWeakHandler]: {} });
+  const listeners = getEventListeners(target, 'foo');
+  deepStrictEqual(listeners, [fn]);
+}