Skip to content

Commit ae50a58

Browse files
committed
add tests
1 parent 71feeb9 commit ae50a58

File tree

2 files changed

+110
-1
lines changed

2 files changed

+110
-1
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { timeoutWithRetry } from './timeout-with-retry';
2+
import { flushPromises } from '../../../../tests/helpers';
3+
4+
describe('timeoutWithRetry', () => {
5+
const timeout = 1000;
6+
7+
beforeEach(() => {
8+
jest.useFakeTimers();
9+
});
10+
11+
afterEach(() => {
12+
jest.useRealTimers();
13+
});
14+
15+
it('returns the result when call completes before timeout', async () => {
16+
const mockCall = jest.fn(async () => 'success');
17+
18+
const resultPromise = timeoutWithRetry(mockCall, timeout, 0);
19+
jest.runAllTimers();
20+
const result = await resultPromise;
21+
22+
expect(result).toBe('success');
23+
expect(mockCall).toHaveBeenCalledTimes(1);
24+
});
25+
26+
describe('retry behaviour', () => {
27+
it('throws when maxRetries is negative', async () => {
28+
const mockCall = jest.fn(async () => 'success');
29+
30+
await expect(() =>
31+
timeoutWithRetry(mockCall, timeout, -1),
32+
).rejects.toThrow('maxRetries must be greater than or equal to 0');
33+
});
34+
35+
it('returns the result when call completes just before timeout', async () => {
36+
const mockCall = createMockCallWithRetries(timeout, 0);
37+
38+
const resultPromise = timeoutWithRetry(mockCall, timeout, 0);
39+
jest.runAllTimers();
40+
const result = await resultPromise;
41+
42+
expect(result).toBe('success');
43+
expect(mockCall).toHaveBeenCalledTimes(1);
44+
});
45+
46+
it('succeeds after multiple retries', async () => {
47+
const mockCall = createMockCallWithRetries(timeout, 2);
48+
49+
const resultPromise = timeoutWithRetry(mockCall, timeout, 3);
50+
jest.runAllTimers();
51+
await flushPromises();
52+
jest.runAllTimers();
53+
const result = await resultPromise;
54+
55+
expect(result).toBe('success');
56+
expect(mockCall).toHaveBeenCalledTimes(3);
57+
});
58+
59+
it('throws when all retries are exhausted', async () => {
60+
const mockCall = createMockCallWithRetries(timeout, 2);
61+
62+
const resultPromise = timeoutWithRetry(mockCall, timeout, 1);
63+
jest.runAllTimers();
64+
await flushPromises();
65+
jest.runAllTimers();
66+
67+
await expect(resultPromise).rejects.toThrow('timeout');
68+
expect(mockCall).toHaveBeenCalledTimes(2);
69+
});
70+
});
71+
72+
describe('non-timeout errors', () => {
73+
it('throws immediately on non-timeout error without retrying', async () => {
74+
const customError = new Error('custom error');
75+
const mockCall = jest.fn(async () => {
76+
throw customError;
77+
});
78+
79+
const resultPromise = timeoutWithRetry(mockCall, timeout, 0);
80+
jest.runAllTimers();
81+
82+
await expect(resultPromise).rejects.toThrow('custom error');
83+
expect(mockCall).toHaveBeenCalledTimes(1);
84+
});
85+
});
86+
});
87+
88+
/**
89+
* @param timeout - The timeout in milliseconds.
90+
* @param timeoutsBeforeSuccess - The number of timeouts before the call succeeds.
91+
* @returns A mock call function that times out for a specific number of times before returning 'success'.
92+
*/
93+
function createMockCallWithRetries(
94+
timeout: number,
95+
timeoutsBeforeSuccess: number,
96+
) {
97+
let callCount = 0;
98+
const mockCall = jest.fn(async () => {
99+
callCount += 1;
100+
101+
if (callCount < timeoutsBeforeSuccess + 1) {
102+
await new Promise((resolve) => setTimeout(resolve, timeout + 1));
103+
}
104+
105+
return 'success';
106+
});
107+
108+
return mockCall;
109+
}

packages/assets-controllers/src/utils/timeout-with-retry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export async function timeoutWithRetry<T extends () => Promise<unknown>>(
1616
maxRetries: number,
1717
// @ts-expect-error TS2366: Assertion guarantees loop executes
1818
): Promise<Awaited<ReturnType<T>>> {
19-
assert(maxRetries > 0, 'maxRetries must be greater than 0');
19+
assert(maxRetries >= 0, 'maxRetries must be greater than or equal to 0');
2020

2121
let attempt = 0;
2222

0 commit comments

Comments
 (0)