Skip to content

Commit ca81e2e

Browse files
🧪 Add tests for testUrls edge cases and fix fallback (#39)
* 🧪 Add tests for testUrls edge cases and fix fallback Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com> * Fix lint issues and missing imports Fixed the unused variables and imported only used values in test Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com> * Fix format issues in tests/http-helper.test.ts Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com>
1 parent c5b138d commit ca81e2e

2 files changed

Lines changed: 62 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: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { describe, expect, test } from 'bun:test';
1+
import { afterEach, describe, expect, mock, test } from 'bun:test';
2+
3+
const runtimeFetchMock = mock(() => Promise.resolve({ status: 200 }));
4+
mock.module('../src/utils/runtime', () => ({
5+
runtimeFetch: runtimeFetchMock,
6+
}));
7+
28
import { promiseAny, testUrls } from '../src/utils/http-helper';
39

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

0 commit comments

Comments
 (0)