Clean up listener and timeout after waitfor reject
This commit is contained in:
@@ -551,6 +551,66 @@ const testEventEmitterWaitForRejectsOnPredicateError = async (): Promise<void> =
|
||||
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);
|
||||
@@ -581,6 +641,11 @@ const runTests = async (): Promise<void> => {
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user