current commit
260828.15 · events: fix weak listener retention overwrite
// Flags: --no-warnings --expose-gc --expose-internals
'use strict';
require('../common');

const assert = require('assert');

const {
  test,
} = require('node:test');

const {
  kWeakHandler,
} = require('internal/event_target');

const { setTimeout: sleep } = require('timers/promises');

// The tests in this file depend on Node.js internal APIs. These are not necessarily
// portable to other runtimes

test('A weak event listener should not prevent gc', async () => {
  // If the event listener is weak, however, it should not prevent gc
  let ref;
  function handler() {}
  {
    ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000));
    ref.deref().addEventListener('abort', handler, { [kWeakHandler]: {} });
  }

  await sleep(10);
  globalThis.gc();
  assert.strictEqual(ref.deref(), undefined);
});

test('two weak listeners with the same retainer should both run on abort', async () => {
  // Regression test for https://github.com/nodejs/node/issues/63954
  const ac = new AbortController();
  let aRan = false;
  let bRan = false;

  ac.signal.addEventListener('a', () => { aRan = true; }, { [kWeakHandler]: ac });
  ac.signal.addEventListener('b', () => { bRan = true; }, { [kWeakHandler]: ac });

  await sleep(10);
  globalThis.gc();

  ac.signal.dispatchEvent(new Event('a'));
  ac.signal.dispatchEvent(new Event('b'));

  assert.strictEqual(aRan, true);
  assert.strictEqual(bRan, true);
});