import { afterAll, beforeAll, describe, expect, test } from 'bun:test'; import { HttpClient, HttpError } from '../src/index'; import { MockServer } from './mock-server'; /** * Integration tests for HTTP client with real network scenarios * These tests use external services and may be affected by network conditions */ let mockServer: MockServer; let mockServerBaseUrl: string; beforeAll(async () => { mockServer = new MockServer(); await mockServer.start(); mockServerBaseUrl = mockServer.getBaseUrl(); }); afterAll(async () => { await mockServer.stop(); }); describe('HTTP Integration Tests', () => { let client: HttpClient; beforeAll(() => { client = new HttpClient({ timeout: 10000, }); }); describe('Real-world scenarios', () => { test('should handle JSON API responses', async () => { try { const response = await client.get('https://jsonplaceholder.typicode.com/posts/1'); expect(response.status).toBe(200); expect(response.data).toHaveProperty('id'); expect(response.data).toHaveProperty('title'); expect(response.data).toHaveProperty('body'); } catch (error) { console.warn('External API test skipped due to network issues:', (error as Error).message); } }); test('should handle large responses', async () => { try { const response = await client.get('https://jsonplaceholder.typicode.com/posts'); expect(response.status).toBe(200); expect(Array.isArray(response.data)).toBe(true); expect(response.data.length).toBeGreaterThan(0); } catch (error) { console.warn( 'Large response test skipped due to network issues:', (error as Error).message ); } }); test('should handle POST with JSON data', async () => { try { const postData = { title: 'Integration Test Post', body: 'This is a test post from integration tests', userId: 1, }; const response = await client.post('https://jsonplaceholder.typicode.com/posts', postData); expect(response.status).toBe(201); expect(response.data).toHaveProperty('id'); expect(response.data.title).toBe(postData.title); } catch (error) { console.warn( 'POST integration test skipped due to network issues:', (error as Error).message ); } }); }); describe('Error scenarios with mock server', () => { test('should handle various HTTP status codes', async () => { const successCodes = [200, 201]; const errorCodes = [400, 401, 403, 404, 500, 503]; // Test success codes for (const statusCode of successCodes) { const response = await client.get(`${mockServerBaseUrl}/status/${statusCode}`); expect(response.status).toBe(statusCode); } // Test error codes (should throw HttpError) for (const statusCode of errorCodes) { await expect(client.get(`${mockServerBaseUrl}/status/${statusCode}`)).rejects.toThrow( HttpError ); } }); test('should handle malformed responses gracefully', async () => { // Mock server returns valid JSON, so this test verifies our client handles it properly const response = await client.get(`${mockServerBaseUrl}/`); expect(response.status).toBe(200); expect(typeof response.data).toBe('object'); }); test('should handle concurrent requests', async () => { const requests = Array.from({ length: 5 }, (_, i) => client.get(`${mockServerBaseUrl}/`, { headers: { 'X-Request-ID': `req-${i}` }, }) ); const responses = await Promise.all(requests); responses.forEach((response, index) => { expect(response.status).toBe(200); expect(response.data.headers).toHaveProperty('x-request-id', `req-${index}`); }); }); }); describe('Performance and reliability', () => { test('should handle rapid sequential requests', async () => { const startTime = Date.now(); const requests = []; for (let i = 0; i < 10; i++) { requests.push(client.get(`${mockServerBaseUrl}/`)); } const responses = await Promise.all(requests); const endTime = Date.now(); expect(responses).toHaveLength(10); responses.forEach(response => { expect(response.status).toBe(200); }); console.log(`Completed 10 requests in ${endTime - startTime}ms`); }); test('should maintain connection efficiency', async () => { const clientWithKeepAlive = new HttpClient({ timeout: 5000, }); const requests = Array.from({ length: 3 }, () => clientWithKeepAlive.get(`${mockServerBaseUrl}/`) ); const responses = await Promise.all(requests); responses.forEach(response => { expect(response.status).toBe(200); }); }); }); });