Add tests for abort fn in exponential backoff
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { expect, test, vi } from 'vitest';
|
import { expect, test, vi } from 'vitest';
|
||||||
import { ExponentialBackoff } from '../source/exponential-backoff.ts';
|
import { ExponentialBackoff } from '../source/exponential-backoff.ts';
|
||||||
import { ExponentialBackoffMaxRetriesHitError } from '../source/errors.ts';
|
import { ExponentialBackoffMaxRetriesHitError, ExponentialBackoffStoppedRetriesError } from '../source/errors.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A valid options object that satisfies {@link ExponentialBackoff.validateOptions}.
|
* A valid options object that satisfies {@link ExponentialBackoff.validateOptions}.
|
||||||
@@ -204,6 +204,97 @@ const testExponentialBackoffWrapsNonErrorThrows = async (): Promise<void> => {
|
|||||||
expect(onError.mock.calls[0][0].message).toBe('not-an-error');
|
expect(onError.mock.calls[0][0].message).toBe('not-an-error');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that when the task function succeeds and the abort signal is aborted, the result is returned
|
||||||
|
* and the onError callback is not called.
|
||||||
|
*/
|
||||||
|
const testExponentialBackoffRunSuccessAndAbortSignal = async (): Promise<void> => {
|
||||||
|
// Define the function which aborts the exponential backoff and succeeds
|
||||||
|
const abortAndSucceedFn = vi.fn(({ stopRetries }) => {
|
||||||
|
stopRetries(new Error('retry me'));
|
||||||
|
|
||||||
|
return Promise.resolve('success');
|
||||||
|
});
|
||||||
|
const onErrorFn = vi.fn();
|
||||||
|
|
||||||
|
// Run the exponential backoff with the function and the onError callback
|
||||||
|
const result = await ExponentialBackoff.run(abortAndSucceedFn, onErrorFn, {
|
||||||
|
baseDelay: 0,
|
||||||
|
jitter: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Expect the result to be the success message
|
||||||
|
expect(result).toBe('success');
|
||||||
|
expect(abortAndSucceedFn).toHaveBeenCalledOnce();
|
||||||
|
|
||||||
|
// Expect the onError callback to not have been called
|
||||||
|
expect(onErrorFn).not.toHaveBeenCalled();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that when the abort signal is aborted with an error, an ExponentialBackoffStoppedRetriesError is thrown
|
||||||
|
* with the error as the message.
|
||||||
|
*/
|
||||||
|
const testExponentialBackoffRunWithAbortSignal = async (): Promise<void> => {
|
||||||
|
// Define the function which aborts the exponential backoff and throws an error
|
||||||
|
const abortAndThrowFn = vi.fn(({ stopRetries }) => {
|
||||||
|
stopRetries(new Error('exponential backoff aborted'));
|
||||||
|
throw new Error('error message');
|
||||||
|
});
|
||||||
|
const onErrorFn = vi.fn();
|
||||||
|
|
||||||
|
// Define the expected error
|
||||||
|
const expectedError = new ExponentialBackoffStoppedRetriesError(new Error('exponential backoff aborted'));
|
||||||
|
|
||||||
|
// Run the exponential backoff with the function and the onError callback and expect the error to be thrown
|
||||||
|
await expect(ExponentialBackoff.run(abortAndThrowFn, onErrorFn, {
|
||||||
|
baseDelay: 0,
|
||||||
|
jitter: 0,
|
||||||
|
})).rejects.toThrow(expectedError);
|
||||||
|
|
||||||
|
// Expect the onError callback to have been called once with the error
|
||||||
|
expect(onErrorFn).toHaveBeenCalledOnce();
|
||||||
|
expect(onErrorFn.mock.calls[0][0]).toBeInstanceOf(Error);
|
||||||
|
expect(onErrorFn.mock.calls[0][0].message).toBe('error message');
|
||||||
|
|
||||||
|
// Expect the function to have been called once and not to have resolved
|
||||||
|
expect(abortAndThrowFn).toHaveBeenCalledOnce();
|
||||||
|
expect(abortAndThrowFn).not.toHaveResolved();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that when the abort signal is aborted with a string, an ExponentialBackoffStoppedRetriesError is thrown
|
||||||
|
* with the string as the message.
|
||||||
|
*/
|
||||||
|
const testExponentialBackoffRunAbortedStringCreatesError = async (): Promise<void> => {
|
||||||
|
// Define the function which aborts the exponential backoff and throws an error
|
||||||
|
const abortAndThrowStringFn = vi.fn(({ stopRetries }) => {
|
||||||
|
stopRetries('exponential backoff aborted');
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
throw 'error message';
|
||||||
|
});
|
||||||
|
const onErrorFn = vi.fn();
|
||||||
|
|
||||||
|
// Define the expected error, Note that we "stopRetries" with just a string, not an error. They are treated equivalently.
|
||||||
|
const expectedError = new ExponentialBackoffStoppedRetriesError(new Error('exponential backoff aborted'));
|
||||||
|
|
||||||
|
// Run the exponential backoff with the function and the onError callback and expect the error to be thrown
|
||||||
|
await expect(ExponentialBackoff.run(abortAndThrowStringFn, onErrorFn, {
|
||||||
|
baseDelay: 0,
|
||||||
|
jitter: 0,
|
||||||
|
})).rejects.toThrow(expectedError);
|
||||||
|
|
||||||
|
// Expect the onError callback to have been called once with the error
|
||||||
|
expect(onErrorFn).toHaveBeenCalledOnce();
|
||||||
|
expect(onErrorFn.mock.calls[0][0]).toBeInstanceOf(Error);
|
||||||
|
expect(onErrorFn.mock.calls[0][0].message).toBe('error message');
|
||||||
|
|
||||||
|
// Expect the function to have been called once and not to have resolved
|
||||||
|
expect(abortAndThrowStringFn).toHaveBeenCalledOnce();
|
||||||
|
expect(abortAndThrowStringFn).not.toHaveResolved();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the {@link ExponentialBackoff.from} factory and subsequent instance {@link ExponentialBackoff.run}
|
* Tests the {@link ExponentialBackoff.from} factory and subsequent instance {@link ExponentialBackoff.run}
|
||||||
* as an alternative to the static helper.
|
* as an alternative to the static helper.
|
||||||
@@ -486,6 +577,9 @@ const runTests = async (): Promise<void> => {
|
|||||||
testExponentialBackoffThrowsMaxRetriesHitErrorWhenExhausted,
|
testExponentialBackoffThrowsMaxRetriesHitErrorWhenExhausted,
|
||||||
);
|
);
|
||||||
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: aborts with abort signal', testExponentialBackoffRunWithAbortSignal);
|
||||||
|
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);
|
||||||
test('ExponentialBackoff: increases delay exponentially between attempts', testExponentialBackoffIncreasesDelayExponentially);
|
test('ExponentialBackoff: increases delay exponentially between attempts', testExponentialBackoffIncreasesDelayExponentially);
|
||||||
|
|||||||
Reference in New Issue
Block a user