Skip to content

Commit cfc29af

Browse files
🧪 Add tests for testUrls edge cases and fix fallback
Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com>
1 parent 2be3698 commit cfc29af

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

‎src/utils/http-helper.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ export const testUrls = async (urls?: string[]) => {
5757
if (!urls?.length) {
5858
return null;
5959
}
60-
const ret = await promiseAny(urls.map(ping));
60+
let ret: string | null = null;
61+
try {
62+
ret = await promiseAny(urls.map(ping));
63+
} catch (e) {
64+
// fallback to urls[0]
65+
}
6166
if (ret) {
6267
return ret;
6368
}

‎tests/http-helper.test.ts‎

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { describe, expect, test } from 'bun:test';
1+
2+
import { describe, expect, test, beforeEach, afterEach, mock } from 'bun:test';
3+
4+
const runtimeFetchMock = mock(() => Promise.resolve({ status: 200 }));
5+
mock.module('../src/utils/runtime', () => ({
6+
runtimeFetch: runtimeFetchMock,
7+
}));
8+
29
import { promiseAny, testUrls } from '../src/utils/http-helper';
310

411
describe('promiseAny', () => {
@@ -41,3 +48,45 @@ describe('testUrls', () => {
4148
expect(result).toBeNull();
4249
});
4350
});
51+
52+
describe('testUrls edge cases', () => {
53+
afterEach(() => {
54+
runtimeFetchMock.mockReset();
55+
});
56+
57+
test('Happy Path: returns successful URL', async () => {
58+
runtimeFetchMock.mockImplementation((url: string) => {
59+
if (url === 'http://success.local') {
60+
return Promise.resolve({ status: 200 });
61+
}
62+
return Promise.reject(new Error('fail'));
63+
});
64+
65+
const result = await testUrls(['http://fail.local', 'http://success.local']);
66+
expect(result).toBe('http://success.local');
67+
});
68+
69+
test('Fastest Response: returns the URL that resolves first', async () => {
70+
runtimeFetchMock.mockImplementation((url: string) => {
71+
if (url === 'http://fast.local') {
72+
return new Promise((resolve) => setTimeout(() => resolve({ status: 200 }), 10));
73+
}
74+
if (url === 'http://slow.local') {
75+
return new Promise((resolve) => setTimeout(() => resolve({ status: 200 }), 50));
76+
}
77+
return Promise.reject(new Error('fail'));
78+
});
79+
80+
const result = await testUrls(['http://slow.local', 'http://fast.local']);
81+
expect(result).toBe('http://fast.local');
82+
});
83+
84+
test('All Failures (Fallback): returns urls[0] without throwing', async () => {
85+
runtimeFetchMock.mockImplementation(() => {
86+
return Promise.resolve({ status: 500 });
87+
});
88+
89+
const result = await testUrls(['http://fail1.local', 'http://fail2.local']);
90+
expect(result).toBe('http://fail1.local');
91+
});
92+
});

0 commit comments

Comments
 (0)