Add test for abort during exponential backoff waiting period

This commit is contained in:
2026-07-21 12:55:22 +10:00
parent 966e361fb3
commit 1511ebaee2

View File

@@ -261,6 +261,46 @@ const testExponentialBackoffRunWithAbortSignal = async (): Promise<void> => {
expect(abortAndThrowFn).not.toHaveResolved(); expect(abortAndThrowFn).not.toHaveResolved();
}; };
/**
* Tests that aborting while the delay between attempts is active rejects the
* pending wait immediately and prevents the next attempt from starting.
*/
const testExponentialBackoffAbortsDuringDelay = async (): Promise<void> => {
vi.useFakeTimers();
try {
let abortRetry: ((reason?: unknown) => void) | undefined;
const rejectedFn = vi.fn(async ({ abort }) => {
abortRetry = abort;
throw new Error('attempt failed');
});
const onError = vi.fn();
const result = ExponentialBackoff.run(rejectedFn, onError, {
baseDelay: 1_000,
maxDelay: 1_000,
maxAttempts: 2,
growthRate: 1,
jitter: 0,
});
// Run the first attempt, enter the retry delay, then stop halfway through it.
await vi.advanceTimersByTimeAsync(500);
expect(abortRetry).toBeDefined();
expect(vi.getTimerCount()).toBe(1);
abortRetry?.(new Error('cancelled during delay'));
await expect(result).rejects.toThrow('Exponential backoff aborted');
expect(rejectedFn).toHaveBeenCalledOnce();
expect(onError).toHaveBeenCalledOnce();
expect(vi.getTimerCount()).toBe(0);
} finally {
vi.useRealTimers();
}
};
/** /**
* Tests that when the abort signal is aborted with a string, an AggregateError is thrown * Tests that when the abort signal is aborted with a string, an AggregateError is thrown
* with the string as the message. * with the string as the message.
@@ -578,6 +618,7 @@ const runTests = async (): Promise<void> => {
test('ExponentialBackoff: wraps non-Error throws before calling onError', testExponentialBackoffWrapsNonErrorThrows); test('ExponentialBackoff: wraps non-Error throws before calling onError', testExponentialBackoffWrapsNonErrorThrows);
test('ExponentialBackoff: succeeds and aborts with abort signal', testExponentialBackoffRunSuccessAndAbortSignal); test('ExponentialBackoff: succeeds and aborts with abort signal', testExponentialBackoffRunSuccessAndAbortSignal);
test('ExponentialBackoff: aborts with abort signal', testExponentialBackoffRunWithAbortSignal); test('ExponentialBackoff: aborts with abort signal', testExponentialBackoffRunWithAbortSignal);
test('ExponentialBackoff: aborts while waiting between attempts', testExponentialBackoffAbortsDuringDelay);
test('ExponentialBackoff: aborts with aborted string creates error', testExponentialBackoffRunAbortedStringCreatesError); test('ExponentialBackoff: aborts with aborted string creates error', testExponentialBackoffRunAbortedStringCreatesError);
test('ExponentialBackoff: works via from and instance run', testExponentialBackoffFromAndInstanceRun); test('ExponentialBackoff: works via from and instance run', testExponentialBackoffFromAndInstanceRun);
test('ExponentialBackoff: retries indefinitely when maxAttempts is 0', testExponentialBackoffRetriesIndefinitelyWhenMaxAttemptsIsZero); test('ExponentialBackoff: retries indefinitely when maxAttempts is 0', testExponentialBackoffRetriesIndefinitelyWhenMaxAttemptsIsZero);