Fix removeAllListeners

This commit is contained in:
2026-08-10 02:03:58 +00:00
parent 099c392dd3
commit e782cace36
2 changed files with 36 additions and 3 deletions
+7 -3
View File
@@ -133,8 +133,8 @@ export class EventEmitter<T extends EventMap> {
listeners.delete(entry); listeners.delete(entry);
}); });
// If no listener was provided, remove the listeners set from the listeners map. // If no listener was provided and no listeners are left for the event type, remove the listeners set from the listeners map.
if (!listener) { if (!listener || this.#listeners.get(type)?.size === 0) {
this.#listeners.delete(type); this.#listeners.delete(type);
} }
} }
@@ -169,7 +169,11 @@ export class EventEmitter<T extends EventMap> {
* Remove all listeners. * Remove all listeners.
*/ */
removeAllListeners(): void { removeAllListeners(): void {
this.#listeners.clear(); for (const [ type, listeners ] of this.#listeners.entries()) {
listeners.forEach((entry) => {
this.off(type, entry.listener);
});
}
} }
/** /**
+29
View File
@@ -305,6 +305,31 @@ const testEventEmitterRemoveAllListeners = (): void => {
expect(countListener).not.toHaveBeenCalled(); expect(countListener).not.toHaveBeenCalled();
}; };
/**
* Tests that removeAllListeners() cancels a pending debounced callback.
*/
const testEventEmitterRemoveAllListenersCancelsPendingDebouncedCallback = async (): Promise<void> => {
vi.useFakeTimers();
try {
const emitter = new EventEmitter<TestEvents>();
const listener = vi.fn();
// Arm a debounce timer, then clear every listener before it expires.
emitter.on('message', listener, 100);
emitter.emit('message', 'should not arrive');
emitter.removeAllListeners();
await vi.advanceTimersByTimeAsync(100);
// Cleared listeners must not receive delayed debounced delivery.
expect(listener).not.toHaveBeenCalled();
} finally {
vi.useRealTimers();
vi.restoreAllMocks();
}
};
/** /**
* Tests that waitFor() resolves when a matching event is emitted. * Tests that waitFor() resolves when a matching event is emitted.
*/ */
@@ -658,6 +683,10 @@ const runTests = async (): Promise<void> => {
testEventEmitterOffCancelsPendingDebouncedCallback, testEventEmitterOffCancelsPendingDebouncedCallback,
); );
test('EventEmitter: removes all listeners when removeAllListeners is called', testEventEmitterRemoveAllListeners); test('EventEmitter: removes all listeners when removeAllListeners is called', testEventEmitterRemoveAllListeners);
test(
'EventEmitter: cancels a pending debounced callback when removeAllListeners is called',
testEventEmitterRemoveAllListenersCancelsPendingDebouncedCallback,
);
test('EventEmitter: resolves waitFor when a matching event is emitted', testEventEmitterWaitForResolvesOnMatch); test('EventEmitter: resolves waitFor when a matching event is emitted', testEventEmitterWaitForResolvesOnMatch);
test('EventEmitter: ignores non-matching events while waiting with waitFor', testEventEmitterWaitForIgnoresNonMatchingEvents); test('EventEmitter: ignores non-matching events while waiting with waitFor', testEventEmitterWaitForIgnoresNonMatchingEvents);
test('EventEmitter: rejects waitFor when the timeout is reached', testEventEmitterWaitForRejectsOnTimeout); test('EventEmitter: rejects waitFor when the timeout is reached', testEventEmitterWaitForRejectsOnTimeout);