import { afterEach, beforeEach, expect, test } from 'bun:test' import { _resetKeepAliveForTesting } from '../../utils/proxy.js' import { fetchWithProxyRetry, isRetryableFetchError, } from './fetchWithProxyRetry.js' type FetchType = typeof globalThis.fetch const originalFetch = globalThis.fetch const originalEnv = { HTTP_PROXY: process.env.HTTP_PROXY, HTTPS_PROXY: process.env.HTTPS_PROXY, } function restoreEnv(key: 'HTTP_PROXY' | 'HTTPS_PROXY', value: string | undefined): void { if (value === undefined) { delete process.env[key] } else { process.env[key] = value } } beforeEach(() => { process.env.HTTP_PROXY = 'http://127.0.0.1:15236' delete process.env.HTTPS_PROXY _resetKeepAliveForTesting() }) afterEach(() => { globalThis.fetch = originalFetch restoreEnv('HTTP_PROXY', originalEnv.HTTP_PROXY) restoreEnv('HTTPS_PROXY', originalEnv.HTTPS_PROXY) _resetKeepAliveForTesting() }) test('isRetryableFetchError matches Bun socket-closed failures', () => { expect( isRetryableFetchError( new Error( 'The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()', ), ), ).toBe(true) }) test('fetchWithProxyRetry retries once with keepalive disabled after socket closure', async () => { const calls: Array = [] globalThis.fetch = (async (_input, init) => { calls.push(init) if (calls.length === 1) { throw new Error( 'The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()', ) } return new Response('ok') }) as FetchType const response = await fetchWithProxyRetry('https://example.com/search', { method: 'POST', }) expect(await response.text()).toBe('ok') expect(calls).toHaveLength(2) expect((calls[0] as RequestInit & { proxy?: string }).proxy).toBe( 'http://127.0.0.1:15236', ) expect((calls[0] as RequestInit).keepalive).toBeUndefined() expect((calls[1] as RequestInit).keepalive).toBe(false) }) test('fetchWithProxyRetry does not retry non-network errors', async () => { let attempts = 0 globalThis.fetch = (async () => { attempts += 1 throw new Error('400 bad request') }) as FetchType await expect(fetchWithProxyRetry('https://example.com')).rejects.toThrow( '400 bad request', ) expect(attempts).toBe(1) })