Fix removeAllListeners
This commit is contained in:
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user