Skip to content

Commit 72f75ff

Browse files
feat(misc): LIT-4017 - Add basic tests for ConditionalRetry
1 parent c1d5394 commit 72f75ff

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { ConditionalRetry, RetryError, TimeoutError, RetryCondition } from './';
2+
3+
describe('ConditionalRetry', () => {
4+
const successfulOperation = jest.fn(async () => 'Success');
5+
const failingOperation = jest.fn(async () => {
6+
throw new Error('Test failure');
7+
});
8+
9+
beforeEach(() => {
10+
jest.clearAllMocks();
11+
});
12+
13+
test('should return the result of a successful operation without retries', async () => {
14+
const retry = new ConditionalRetry({
15+
operation: successfulOperation,
16+
globalMaxRetries: 3,
17+
timeoutSeconds: 5,
18+
});
19+
20+
const result = await retry.start();
21+
expect(result).toBe('Success');
22+
expect(successfulOperation).toHaveBeenCalledTimes(1);
23+
});
24+
25+
test('should retry on failure and eventually succeed', async () => {
26+
const operation = jest
27+
.fn()
28+
.mockRejectedValueOnce(new Error('Temporary error'))
29+
.mockResolvedValueOnce('Success');
30+
31+
const retry = new ConditionalRetry({
32+
operation,
33+
globalMaxRetries: 3,
34+
timeoutSeconds: 5,
35+
});
36+
37+
const result = await retry.start();
38+
expect(result).toBe('Success');
39+
expect(operation).toHaveBeenCalledTimes(2); // 1 failure + 1 success
40+
});
41+
42+
test('should retry based on condition and fail after condition max retries', async () => {
43+
const condition: RetryCondition = {
44+
maxRetries: 2,
45+
attempts: 1,
46+
backoffType: 'fixed',
47+
baseDelay: 100,
48+
shouldRetry: (error) => error.message === 'Condition failure',
49+
};
50+
51+
const retry = new ConditionalRetry({
52+
operation: failingOperation,
53+
globalMaxRetries: 5,
54+
timeoutSeconds: 5,
55+
conditions: [condition],
56+
});
57+
58+
await expect(retry.start()).rejects.toThrow(RetryError);
59+
expect(failingOperation).toHaveBeenCalledTimes(5); // 1 initial attempt + 2 retries from condition + 2 more from globalMaxRetries
60+
});
61+
62+
test('should retry up to global max retries if no condition matches', async () => {
63+
const retry = new ConditionalRetry({
64+
operation: failingOperation,
65+
globalMaxRetries: 3,
66+
timeoutSeconds: 5,
67+
});
68+
69+
await expect(retry.start()).rejects.toThrow(RetryError);
70+
expect(failingOperation).toHaveBeenCalledTimes(3); // Retry up to globalMaxRetries
71+
});
72+
73+
test('should honor global max retries even if a condition exists but is not matched', async () => {
74+
const condition: RetryCondition = {
75+
maxRetries: 2,
76+
attempts: 1,
77+
backoffType: 'fixed',
78+
baseDelay: 100,
79+
shouldRetry: (error) => error.message === 'Non-matching error',
80+
};
81+
82+
const retry = new ConditionalRetry({
83+
operation: failingOperation,
84+
globalMaxRetries: 3,
85+
timeoutSeconds: 5,
86+
conditions: [condition],
87+
});
88+
89+
await expect(retry.start()).rejects.toThrow(RetryError);
90+
expect(failingOperation).toHaveBeenCalledTimes(3); // Retries up to the global max
91+
});
92+
93+
test('should timeout if the operation does not complete within the specified time', async () => {
94+
const longOperation = jest.fn(
95+
() => new Promise((resolve, reject) => setTimeout(reject, 3000))
96+
);
97+
98+
const retry = new ConditionalRetry({
99+
operation: longOperation,
100+
globalMaxRetries: 3,
101+
timeoutSeconds: 2,
102+
});
103+
104+
await expect(retry.start()).rejects.toThrow(TimeoutError);
105+
expect(longOperation).toHaveBeenCalledTimes(1); // Only one attempt due to timeout
106+
});
107+
});

0 commit comments

Comments
 (0)