709 lines
24 KiB
TypeScript
709 lines
24 KiB
TypeScript
import { expect, test, vi } from 'vitest';
|
|
import { EventEmitter } from '../source/event-emitter.ts';
|
|
|
|
/** Simple event map used across these tests. */
|
|
type TestEvents = {
|
|
message: string;
|
|
count: number;
|
|
};
|
|
|
|
/**
|
|
* Tests that EventEmitter invokes listeners when an event is emitted.
|
|
*/
|
|
const testEventEmitterCallsListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
// Register the listener and emit an event.
|
|
emitter.on('message', listener);
|
|
emitter.emit('message', 'hello');
|
|
|
|
// Expect the listener to have been called with the emitted payload.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith('hello');
|
|
};
|
|
|
|
/**
|
|
* Tests that EventEmitter invokes all listeners registered for the same event.
|
|
*/
|
|
const testEventEmitterCallsMultipleListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const firstListener = vi.fn();
|
|
const secondListener = vi.fn();
|
|
|
|
// Register two listeners for the same event type.
|
|
emitter.on('count', firstListener);
|
|
emitter.on('count', secondListener);
|
|
emitter.emit('count', 42);
|
|
|
|
// Expect both listeners to receive the same payload.
|
|
expect(firstListener).toHaveBeenCalledOnce();
|
|
expect(firstListener).toHaveBeenCalledWith(42);
|
|
expect(secondListener).toHaveBeenCalledOnce();
|
|
expect(secondListener).toHaveBeenCalledWith(42);
|
|
};
|
|
|
|
/**
|
|
* Tests that EventEmitter only invokes listeners registered for the emitted event type.
|
|
*/
|
|
const testEventEmitterCallsOnlyMatchingListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const messageListener = vi.fn();
|
|
const countListener = vi.fn();
|
|
|
|
// Register listeners on different event types.
|
|
emitter.on('message', messageListener);
|
|
emitter.on('count', countListener);
|
|
|
|
// Emit only the message event.
|
|
emitter.emit('message', 'hello');
|
|
|
|
// Expect only the matching listener to have been called.
|
|
expect(messageListener).toHaveBeenCalledOnce();
|
|
expect(countListener).not.toHaveBeenCalled();
|
|
};
|
|
|
|
/**
|
|
* Tests that EventEmitter.emit returns false when no listeners are registered.
|
|
*/
|
|
const testEventEmitterEmitReturnsFalseWithNoListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
const hasListeners = emitter.emit('message', 'hello');
|
|
|
|
// Expect emit to report that nobody was listening.
|
|
expect(hasListeners).toBe(false);
|
|
};
|
|
|
|
/**
|
|
* Tests that EventEmitter.emit returns true when listeners are registered.
|
|
*/
|
|
const testEventEmitterEmitReturnsTrueWithListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
emitter.on('message', vi.fn());
|
|
|
|
const hasListeners = emitter.emit('message', 'hello');
|
|
|
|
// Expect emit to report that at least one listener was invoked.
|
|
expect(hasListeners).toBe(true);
|
|
};
|
|
|
|
/**
|
|
* Tests that emitted events cannot be mutated.
|
|
*/
|
|
const testEventEmitterEmittedEventsCannotBeMutated = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
const payload = { nested: { value: 1 } };
|
|
|
|
emitter.on('nested', listener, 100);
|
|
|
|
// Arm the debounce timer with the current payload.
|
|
emitter.emit('nested', payload);
|
|
|
|
// Mutate the original object while the timer is still pending.
|
|
payload.nested.value = 999;
|
|
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
// The listener must receive a snapshot from emit time, not the mutated value.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
|
|
// Expect the listener to have received the original payload object without any mutations
|
|
expect(listener).toHaveBeenCalledWith({
|
|
nested: {
|
|
value: 1,
|
|
},
|
|
});
|
|
|
|
// Expect the payload object to have been mutated
|
|
expect(payload).toStrictEqual({
|
|
nested: {
|
|
value: 999,
|
|
},
|
|
});
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that the off callback returned by on() removes the listener.
|
|
*/
|
|
const testEventEmitterOffCallbackRemovesListener = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
// on() returns an off callback that removes the listener.
|
|
const off = emitter.on('message', listener);
|
|
emitter.emit('message', 'first');
|
|
|
|
// Unsubscribe before emitting again.
|
|
off();
|
|
emitter.emit('message', 'second');
|
|
|
|
// Expect the listener to have only received the first event.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith('first');
|
|
};
|
|
|
|
/**
|
|
* Tests that off() removes a listener when given the same function reference.
|
|
*/
|
|
const testEventEmitterOffRemovesListenerByReference = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('message', listener);
|
|
emitter.off('message', listener);
|
|
emitter.emit('message', 'hello');
|
|
|
|
// Expect the listener to have been removed before the emit.
|
|
expect(listener).not.toHaveBeenCalled();
|
|
};
|
|
|
|
/**
|
|
* Tests that off() removes all listeners for an event type when no listener is provided.
|
|
*/
|
|
const testEventEmitterOffRemovesAllListenersForEventType = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('message', listener);
|
|
emitter.off('message');
|
|
|
|
expect(listener).not.toHaveBeenCalled();
|
|
expect(emitter.emit('message', 'hello')).toBe(false);
|
|
expect(emitter.emit('count', 42)).toBe(false);
|
|
};
|
|
|
|
/**
|
|
* Tests that off() does nothing when given an unknown listener reference.
|
|
*/
|
|
const testEventEmitterOffIgnoresUnknownListener = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('message', listener);
|
|
|
|
// Try to remove a different function reference.
|
|
emitter.off('message', vi.fn());
|
|
emitter.emit('message', 'hello');
|
|
|
|
// Expect the original listener to still receive the event.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
};
|
|
|
|
/**
|
|
* Tests that off() does nothing when called for an event type with no listeners.
|
|
*/
|
|
const testEventEmitterOffIgnoresUnregisteredEventType = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
// Call off without ever registering this listener.
|
|
emitter.off('message', listener);
|
|
|
|
expect(listener).not.toHaveBeenCalled();
|
|
};
|
|
|
|
/**
|
|
* Tests that once() listeners are invoked only one time.
|
|
*/
|
|
const testEventEmitterOnceListenerFiresOnce = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.once('message', listener);
|
|
emitter.emit('message', 'first');
|
|
emitter.emit('message', 'second');
|
|
|
|
// Expect the listener to auto-unsubscribe after the first emit.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith('first');
|
|
};
|
|
|
|
/**
|
|
* Tests that once() can be added when regular listeners already exist for the event type.
|
|
*/
|
|
const testEventEmitterOnceWorksWithExistingListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const existingListener = vi.fn();
|
|
const onceListener = vi.fn();
|
|
|
|
// Register a regular listener first so the event type already exists in the map.
|
|
emitter.on('message', existingListener);
|
|
emitter.once('message', onceListener);
|
|
emitter.emit('message', 'hello');
|
|
|
|
expect(existingListener).toHaveBeenCalledOnce();
|
|
expect(onceListener).toHaveBeenCalledOnce();
|
|
};
|
|
|
|
/**
|
|
* Tests that the off callback returned by once() removes the listener before it fires.
|
|
*/
|
|
const testEventEmitterOnceOffCallbackRemovesListener = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
const off = emitter.once('message', listener);
|
|
|
|
// Unsubscribe before the event is ever emitted.
|
|
off();
|
|
emitter.emit('message', 'hello');
|
|
|
|
expect(listener).not.toHaveBeenCalled();
|
|
};
|
|
|
|
/**
|
|
* Tests that debounced listeners do not receive the debounced event if the listener is removed.
|
|
*/
|
|
const testEventEmitterOffCancelsPendingDebouncedCallback = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
const off = emitter.on('message', listener, 100);
|
|
emitter.emit('message', 'first');
|
|
|
|
off();
|
|
emitter.emit('message', 'second');
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
expect(listener).not.toHaveBeenCalled();
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that removeAllListeners() clears every registered listener.
|
|
*/
|
|
const testEventEmitterRemoveAllListeners = (): void => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const messageListener = vi.fn();
|
|
const countListener = vi.fn();
|
|
|
|
emitter.on('message', messageListener);
|
|
emitter.on('count', countListener);
|
|
emitter.removeAllListeners();
|
|
|
|
// Emit on both event types after clearing all listeners.
|
|
emitter.emit('message', 'hello');
|
|
emitter.emit('count', 1);
|
|
|
|
expect(messageListener).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.
|
|
*/
|
|
const testEventEmitterWaitForResolvesOnMatch = async (): Promise<void> => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
// Wait until an event matches the predicate.
|
|
const waitPromise = emitter.waitFor('count', (payload) => payload === 42);
|
|
|
|
// Emit a non-matching event first, then the matching one.
|
|
emitter.emit('count', 41);
|
|
emitter.emit('count', 42);
|
|
|
|
await expect(waitPromise).resolves.toBe(42);
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() ignores non-matching events while other listeners still receive them.
|
|
*/
|
|
const testEventEmitterWaitForIgnoresNonMatchingEvents = async (): Promise<void> => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
const waitPromise = emitter.waitFor('message', (payload) => payload === 'done');
|
|
|
|
// A regular listener should still receive every emit while waitFor filters.
|
|
emitter.on('message', listener);
|
|
emitter.emit('message', 'pending');
|
|
emitter.emit('message', 'done');
|
|
|
|
await expect(waitPromise).resolves.toBe('done');
|
|
expect(listener).toHaveBeenCalledTimes(2);
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() rejects when the timeout expires.
|
|
*/
|
|
const testEventEmitterWaitForRejectsOnTimeout = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
const waitPromise = emitter.waitFor('message', () => true, 100);
|
|
|
|
// Attach the rejection handler before advancing timers so the rejection is handled.
|
|
const assertion = expect(waitPromise).rejects.toThrow('Timeout waiting for event "message"');
|
|
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
await assertion;
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() clears its timeout when it resolves before expiry.
|
|
*/
|
|
const testEventEmitterWaitForClearsTimeoutOnResolve = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
// Register waitFor with a timeout, then resolve it before the timer fires.
|
|
const waitPromise = emitter.waitFor('message', (payload) => payload === 'done', 100);
|
|
|
|
emitter.emit('message', 'done');
|
|
|
|
await expect(waitPromise).resolves.toBe('done');
|
|
|
|
// If clearTimeout was not called, advancing past the timeout would reject the promise.
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() removes its listener after resolving.
|
|
*/
|
|
const testEventEmitterWaitForRemovesListenerAfterResolve = async (): Promise<void> => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
const waitPromise = emitter.waitFor('message', () => true);
|
|
|
|
emitter.emit('message', 'first');
|
|
await expect(waitPromise).resolves.toBe('first');
|
|
|
|
// Register a second waitFor so we can verify the first listener was cleaned up.
|
|
const secondWaitPromise = emitter.waitFor('message', (payload) => payload === 'second');
|
|
|
|
// Emit a payload that only the second waitFor should accept.
|
|
emitter.emit('message', 'ignored');
|
|
|
|
// Track whether the second waitFor resolves too early.
|
|
let resolvedEarly = false;
|
|
/* eslint-disable-next-line */
|
|
secondWaitPromise.then(() => {
|
|
resolvedEarly = true;
|
|
});
|
|
|
|
// Yield so any premature resolution would have a chance to run.
|
|
await Promise.resolve();
|
|
expect(resolvedEarly).toBe(false);
|
|
|
|
emitter.emit('message', 'second');
|
|
await expect(secondWaitPromise).resolves.toBe('second');
|
|
};
|
|
|
|
/**
|
|
* Tests that the first debounced emit does not call clearTimeout.
|
|
*/
|
|
const testEventEmitterDebouncedFirstEmitDoesNotClearTimeout = (): void => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const clearTimeoutSpy = vi.spyOn(globalThis, 'clearTimeout');
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('message', listener, 100);
|
|
emitter.emit('message', 'first');
|
|
|
|
// The first emit starts the debounce timer; there is nothing to clear yet.
|
|
expect(clearTimeoutSpy).not.toHaveBeenCalled();
|
|
expect(listener).not.toHaveBeenCalled();
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that debounced on() listeners receive only the last payload after the debounce window.
|
|
*/
|
|
const testEventEmitterDebouncedOnListener = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('message', listener, 100);
|
|
|
|
// Emit several events in quick succession.
|
|
emitter.emit('message', 'first');
|
|
emitter.emit('message', 'second');
|
|
emitter.emit('message', 'third');
|
|
|
|
// Expect the listener to not have fired yet.
|
|
expect(listener).not.toHaveBeenCalled();
|
|
|
|
// Advance past the debounce window.
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
// Expect only the last payload to have been delivered.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith('third');
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that repeated debounced emits reset the debounce timer.
|
|
*/
|
|
const testEventEmitterDebouncedTimerResetsOnRepeatedEmits = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.on('count', listener, 100);
|
|
emitter.emit('count', 1);
|
|
|
|
// Advance halfway through the debounce window and emit again.
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
emitter.emit('count', 2);
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
|
|
// The timer was reset, so the listener should not have fired yet.
|
|
expect(listener).not.toHaveBeenCalled();
|
|
|
|
// Advance the remaining time for the reset timer to expire.
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith(2);
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that a debounce time of zero behaves like a normal listener.
|
|
*/
|
|
const testEventEmitterZeroDebounceDoesNotDebounce = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
// A debounce time of zero should behave like a normal listener.
|
|
emitter.on('message', listener, 0);
|
|
emitter.emit('message', 'first');
|
|
emitter.emit('message', 'second');
|
|
|
|
expect(listener).toHaveBeenCalledTimes(2);
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that debounced once() listeners fire once with the last payload.
|
|
*/
|
|
const testEventEmitterDebouncedOnceListener = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
emitter.once('message', listener, 100);
|
|
emitter.emit('message', 'first');
|
|
emitter.emit('message', 'second');
|
|
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
// Expect the debounced once listener to fire once with the last payload.
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
expect(listener).toHaveBeenCalledWith('second');
|
|
|
|
// Emit again after the debounce window; the once listener should stay removed.
|
|
emitter.emit('message', 'third');
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
expect(listener).toHaveBeenCalledOnce();
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tests that the `waitFor` method rejects if the predicate function throws
|
|
*/
|
|
const testEventEmitterWaitForRejectsOnPredicateError = async (): Promise<void> => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const listener = vi.fn();
|
|
|
|
const waitPromise = emitter.waitFor('message', () => {
|
|
throw new Error('predicate error');
|
|
});
|
|
|
|
emitter.emit('message', 'hello');
|
|
|
|
await expect(waitPromise).rejects.toThrow('predicate error');
|
|
expect(listener).not.toHaveBeenCalled();
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() removes its listener after the predicate function throws an error.
|
|
*/
|
|
const testEventEmitterWaitForRemovesListenerAfterPredicateError = async (): Promise<void> => {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
|
|
// Create a predicate function that throws an error.
|
|
const predicate = vi.fn().mockImplementation(() => {
|
|
throw new Error('predicate error');
|
|
});
|
|
|
|
// Wait for the predicate function to throw an error.
|
|
const waitPromise = emitter.waitFor('message', predicate);
|
|
|
|
// Emit an event, expecting the predicate function to throw an error.
|
|
emitter.emit('message', 'hello');
|
|
await expect(waitPromise).rejects.toThrow('predicate error');
|
|
|
|
// Expect the predicate function to have been called once.
|
|
expect(predicate).toHaveBeenCalledTimes(1);
|
|
|
|
// A later emit must not invoke the failed waitFor predicate again.
|
|
emitter.emit('message', 'again');
|
|
|
|
// Expect the predicate function to still have been called once.
|
|
expect(predicate).toHaveBeenCalledTimes(1);
|
|
};
|
|
|
|
/**
|
|
* Tests that waitFor() clears its timeout when the predicate function throws an error.
|
|
*/
|
|
const testEventEmitterWaitForClearsTimeoutAfterPredicateError = async (): Promise<void> => {
|
|
vi.useFakeTimers();
|
|
|
|
try {
|
|
const emitter = new EventEmitter<TestEvents>();
|
|
const clearTimeoutSpy = vi.spyOn(globalThis, 'clearTimeout');
|
|
|
|
const waitPromise = emitter.waitFor(
|
|
'message',
|
|
(): boolean => {
|
|
throw new Error('predicate error');
|
|
},
|
|
100,
|
|
);
|
|
|
|
emitter.emit('message', 'hello');
|
|
await expect(waitPromise).rejects.toThrow('predicate error');
|
|
|
|
// The timeout scheduled for waitFor must be cleared on predicate failure.
|
|
expect(clearTimeoutSpy).toHaveBeenCalled();
|
|
|
|
// Advancing past the original timeout must not produce a second rejection path.
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
} finally {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
}
|
|
};
|
|
|
|
const runTests = async (): Promise<void> => {
|
|
test('EventEmitter: calls listeners when an event is emitted', testEventEmitterCallsListeners);
|
|
test('EventEmitter: calls multiple listeners for the same event', testEventEmitterCallsMultipleListeners);
|
|
test('EventEmitter: only calls listeners for the emitted event type', testEventEmitterCallsOnlyMatchingListeners);
|
|
test('EventEmitter: returns false when emitting with no listeners', testEventEmitterEmitReturnsFalseWithNoListeners);
|
|
test('EventEmitter: returns true when emitting with listeners', testEventEmitterEmitReturnsTrueWithListeners);
|
|
test('EventEmitter: emitted events cannot be mutated', testEventEmitterEmittedEventsCannotBeMutated);
|
|
test('EventEmitter: stops calling a listener after its off callback is invoked', testEventEmitterOffCallbackRemovesListener);
|
|
test('EventEmitter: removes a listener when off is called with the same reference', testEventEmitterOffRemovesListenerByReference);
|
|
test(
|
|
'EventEmitter: removes all listeners for an event type when off is called with no listener',
|
|
testEventEmitterOffRemovesAllListenersForEventType,
|
|
);
|
|
test('EventEmitter: ignores off when the listener reference is unknown', testEventEmitterOffIgnoresUnknownListener);
|
|
test('EventEmitter: ignores off for an event type with no listeners', testEventEmitterOffIgnoresUnregisteredEventType);
|
|
test('EventEmitter: calls a once listener only one time', testEventEmitterOnceListenerFiresOnce);
|
|
test('EventEmitter: registers once when listeners already exist', testEventEmitterOnceWorksWithExistingListeners);
|
|
test('EventEmitter: stops a once listener after its off callback is invoked', testEventEmitterOnceOffCallbackRemovesListener);
|
|
test(
|
|
'EventEmitter: debounced listeners do not receive the debounced event if the listener is removed',
|
|
testEventEmitterOffCancelsPendingDebouncedCallback,
|
|
);
|
|
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: ignores non-matching events while waiting with waitFor', testEventEmitterWaitForIgnoresNonMatchingEvents);
|
|
test('EventEmitter: rejects waitFor when the timeout is reached', testEventEmitterWaitForRejectsOnTimeout);
|
|
test('EventEmitter: clears the timeout when waitFor resolves before expiry', testEventEmitterWaitForClearsTimeoutOnResolve);
|
|
test('EventEmitter: removes the waitFor listener after it resolves', testEventEmitterWaitForRemovesListenerAfterResolve);
|
|
test('EventEmitter: does not clear a timeout on the first debounced emit', testEventEmitterDebouncedFirstEmitDoesNotClearTimeout);
|
|
test('EventEmitter: debounces on listeners', testEventEmitterDebouncedOnListener);
|
|
test('EventEmitter: resets the debounce timer on repeated emits', testEventEmitterDebouncedTimerResetsOnRepeatedEmits);
|
|
test('EventEmitter: does not debounce when debounceMilliseconds is zero', testEventEmitterZeroDebounceDoesNotDebounce);
|
|
test('EventEmitter: debounces once listeners and invokes them only once', testEventEmitterDebouncedOnceListener);
|
|
test('EventEmitter: rejects waitFor when the predicate function throws', testEventEmitterWaitForRejectsOnPredicateError);
|
|
test(
|
|
'EventEmitter: removes the waitFor listener after it rejects due to predicate error',
|
|
testEventEmitterWaitForRemovesListenerAfterPredicateError,
|
|
);
|
|
test('EventEmitter: clears the timeout when waitFor rejects due to predicate error', testEventEmitterWaitForClearsTimeoutAfterPredicateError);
|
|
};
|
|
|
|
await runTests();
|