import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'bun:test'; import { HttpClient, HttpError, ProxyManager } from '../src/index'; import type { ProxyInfo } from '../src/types'; import { MockServer } from './mock-server'; // Global mock server instance let mockServer: MockServer; let mockServerBaseUrl: string; beforeAll(async () => { // Start mock server for all tests mockServer = new MockServer(); await mockServer.start(); mockServerBaseUrl = mockServer.getBaseUrl(); }); afterAll(async () => { // Stop mock server await mockServer.stop(); }); describe('HttpClient', () => { let client: HttpClient; beforeEach(() => { client = new HttpClient(); }); describe('Basic functionality', () => { test('should create client with default config', () => { expect(client).toBeInstanceOf(HttpClient); }); test('should make GET request', async () => { const response = await client.get(`${mockServerBaseUrl}/`); expect(response.status).toBe(200); expect(response.data).toHaveProperty('url'); expect(response.data).toHaveProperty('method', 'GET'); }); test('should make POST request with body', async () => { const testData = { title: 'Test Post', body: 'Test body', userId: 1, }; const response = await client.post(`${mockServerBaseUrl}/post`, testData); expect(response.status).toBe(200); expect(response.data).toHaveProperty('data'); expect(response.data.data).toEqual(testData); }); test('should handle custom headers', async () => { const customHeaders = { 'X-Custom-Header': 'test-value', 'User-Agent': 'StockBot-HTTP-Client/1.0', }; const response = await client.get(`${mockServerBaseUrl}/headers`, { headers: customHeaders, }); expect(response.status).toBe(200); expect(response.data.headers).toHaveProperty('x-custom-header', 'test-value'); expect(response.data.headers).toHaveProperty('user-agent', 'StockBot-HTTP-Client/1.0'); }); test('should handle timeout', async () => { const clientWithTimeout = new HttpClient({ timeout: 1 }); // 1ms timeout await expect(clientWithTimeout.get('https://httpbin.org/delay/1')).rejects.toThrow(); }); }); describe('Error handling', () => { test('should handle HTTP errors', async () => { await expect(client.get(`${mockServerBaseUrl}/status/404`)).rejects.toThrow(HttpError); }); test('should handle network errors gracefully', async () => { await expect( client.get('https://nonexistent-domain-that-will-fail-12345.test') ).rejects.toThrow(); }); test('should handle invalid URLs', async () => { await expect(client.get('not:/a:valid/url')).rejects.toThrow(); }); }); describe('HTTP methods', () => { test('should make PUT request', async () => { const testData = { id: 1, name: 'Updated' }; const response = await client.put(`${mockServerBaseUrl}/post`, testData); expect(response.status).toBe(200); }); test('should make DELETE request', async () => { const response = await client.del(`${mockServerBaseUrl}/`); expect(response.status).toBe(200); expect(response.data.method).toBe('DELETE'); }); test('should make PATCH request', async () => { const testData = { name: 'Patched' }; const response = await client.patch(`${mockServerBaseUrl}/post`, testData); expect(response.status).toBe(200); }); }); }); describe('ProxyManager', () => { test('should determine when to use Bun fetch', () => { const httpProxy: ProxyInfo = { protocol: 'http', host: 'proxy.example.com', port: 8080, }; const socksProxy: ProxyInfo = { protocol: 'socks5', host: 'proxy.example.com', port: 1080, }; expect(ProxyManager.shouldUseBunFetch(httpProxy)).toBe(true); expect(ProxyManager.shouldUseBunFetch(socksProxy)).toBe(false); }); test('should create proxy URL for Bun fetch', () => { const proxy: ProxyInfo = { protocol: 'http', host: 'proxy.example.com', port: 8080, username: 'user', password: 'pass', }; const proxyUrl = ProxyManager.createProxyUrl(proxy); expect(proxyUrl).toBe('http://user:pass@proxy.example.com:8080'); }); test('should create proxy URL without credentials', () => { const proxy: ProxyInfo = { protocol: 'https', host: 'proxy.example.com', port: 8080, }; const proxyUrl = ProxyManager.createProxyUrl(proxy); expect(proxyUrl).toBe('https://proxy.example.com:8080'); }); });