/** * Contract test for IUniversalHttpClient.registerPlatform() * * This test validates the platform registration functionality of the Universal HTTP Client * according to the contract specification. Tests MUST FAIL until implementation is complete. */ import { describe, test, expect, beforeEach, jest } from '@jest/globals' // Import types that will be implemented import type { IUniversalHttpClient, IPlatformAdapter, HealthStatus } from '@/types/httpClientCore' describe('IUniversalHttpClient.registerPlatform() Contract', () => { let httpClient: IUniversalHttpClient beforeEach(() => { // This will fail until IUniversalHttpClient is implemented // eslint-disable-next-line @typescript-eslint/no-require-imports const { HttpClientCore } = require('@/core/http-client/HttpClientCore') httpClient = new HttpClientCore() }) describe('Platform Registration', () => { test('should register a new platform adapter successfully', () => { const mockAdapter: IPlatformAdapter = { platform: 'test-platform', baseUrl: 'https://api.test-platform.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } expect(() => { httpClient.registerPlatform('test-platform', mockAdapter) }).not.toThrow() // Verify the platform is registered by checking if it's available for requests expect(httpClient.isPlatformRegistered?.('test-platform')).toBe(true) }) test('should register multiple platform adapters', () => { const adapters = [ { platform: 'platform-1', baseUrl: 'https://api.platform-1.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) }, { platform: 'platform-2', baseUrl: 'https://api.platform-2.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } ] adapters.forEach(adapter => { expect(() => { httpClient.registerPlatform(adapter.platform, adapter as IPlatformAdapter) }).not.toThrow() }) // Verify both platforms are registered expect(httpClient.isPlatformRegistered?.('platform-1')).toBe(true) expect(httpClient.isPlatformRegistered?.('platform-2')).toBe(true) }) test('should replace existing platform adapter when re-registered', () => { const originalAdapter: IPlatformAdapter = { platform: 'replaceable-platform', baseUrl: 'https://api.original.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } const newAdapter: IPlatformAdapter = { platform: 'replaceable-platform', baseUrl: 'https://api.new.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } // Register original adapter httpClient.registerPlatform('replaceable-platform', originalAdapter) expect(httpClient.isPlatformRegistered?.('replaceable-platform')).toBe(true) // Register new adapter with same platform name httpClient.registerPlatform('replaceable-platform', newAdapter) expect(httpClient.isPlatformRegistered?.('replaceable-platform')).toBe(true) // Verify the new adapter is being used (baseUrl should be from new adapter) const registeredAdapter = httpClient.getPlatformAdapter?.('replaceable-platform') expect(registeredAdapter?.baseUrl).toBe('https://api.new.com') }) test('should validate adapter configuration before registration', () => { const invalidAdapter: IPlatformAdapter = { platform: 'invalid-platform', baseUrl: 'https://api.invalid.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(false) // Invalid configuration } expect(() => { httpClient.registerPlatform('invalid-platform', invalidAdapter) }).toThrow('Invalid platform configuration') }) }) describe('Platform Access', () => { test('should provide access to registered platform adapters', () => { const adapter: IPlatformAdapter = { platform: 'accessible-platform', baseUrl: 'https://api.accessible.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform('accessible-platform', adapter) const retrievedAdapter = httpClient.getPlatformAdapter?.('accessible-platform') expect(retrievedAdapter).toBeDefined() expect(retrievedAdapter?.platform).toBe('accessible-platform') expect(retrievedAdapter?.baseUrl).toBe('https://api.accessible.com') }) test('should return list of registered platforms', () => { const platforms = ['platform-a', 'platform-b', 'platform-c'] platforms.forEach(platform => { const adapter: IPlatformAdapter = { platform, baseUrl: `https://api.${platform}.com`, request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform(platform, adapter) }) const registeredPlatforms = httpClient.getRegisteredPlatforms?.() expect(registeredPlatforms).toEqual(expect.arrayContaining(platforms)) expect(registeredPlatforms).toHaveLength(platforms.length) }) test('should check if specific platform is registered', () => { const adapter: IPlatformAdapter = { platform: 'checkable-platform', baseUrl: 'https://api.checkable.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } expect(httpClient.isPlatformRegistered?.('checkable-platform')).toBe(false) httpClient.registerPlatform('checkable-platform', adapter) expect(httpClient.isPlatformRegistered?.('checkable-platform')).toBe(true) expect(httpClient.isPlatformRegistered?.('non-existent-platform')).toBe(false) }) }) describe('Platform Management', () => { test('should support unregistering platforms', async () => { const adapter: IPlatformAdapter = { platform: 'removable-platform', baseUrl: 'https://api.removable.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform('removable-platform', adapter) expect(httpClient.isPlatformRegistered?.('removable-platform')).toBe(true) const result = await httpClient.unregisterPlatform?.('removable-platform') expect(result?.success).toBe(true) expect(httpClient.isPlatformRegistered?.('removable-platform')).toBe(false) }) test('should support updating platform configuration', async () => { const adapter: IPlatformAdapter = { platform: 'updatable-platform', baseUrl: 'https://api.updatable.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform('updatable-platform', adapter) const updatedConfig = { baseUrl: 'https://api.updated.com', timeout: { connect: 10000, read: 60000, write: 30000 } } const result = await httpClient.updatePlatformConfig?.('updatable-platform', updatedConfig) expect(result?.success).toBe(true) const retrievedAdapter = httpClient.getPlatformAdapter?.('updatable-platform') expect(retrievedAdapter?.baseUrl).toBe('https://api.updated.com') }) test('should provide platform configuration information', () => { const adapter: IPlatformAdapter = { platform: 'info-platform', baseUrl: 'https://api.info.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn().mockReturnValue({ platform: 'info-platform', baseUrl: 'https://api.info.com', authConfig: { type: 'signature' }, timeouts: { connect: 5000, read: 30000, write: 15000 } }), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform('info-platform', adapter) const platformInfo = httpClient.getPlatformInfo?.('info-platform') expect(platformInfo).toBeDefined() expect(platformInfo?.platform).toBe('info-platform') expect(platformInfo?.baseUrl).toBe('https://api.info.com') }) }) describe('Health and Status', () => { test('should provide overall client health status', async () => { const adapters = [ { platform: 'healthy-platform-1', baseUrl: 'https://api.healthy1.com', checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 50 }) }, { platform: 'healthy-platform-2', baseUrl: 'https://api.healthy2.com', checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 75 }) } ] adapters.forEach(adapter => { const fullAdapter: IPlatformAdapter = { ...adapter, request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform(adapter.platform, fullAdapter) }) const health: HealthStatus = await httpClient.getHealth() expect(health).toBeDefined() expect(health.status).toBe('healthy') expect(health.platforms).toBeDefined() expect(Object.keys(health.platforms)).toHaveLength(2) expect(health.platforms['healthy-platform-1']?.status).toBe('healthy') expect(health.platforms['healthy-platform-2']?.status).toBe('healthy') }) test('should detect unhealthy platforms', async () => { const adapters = [ { platform: 'healthy-platform', baseUrl: 'https://api.healthy.com', checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 50 }) }, { platform: 'unhealthy-platform', baseUrl: 'https://api.unhealthy.com', checkHealth: jest.fn().mockRejectedValue(new Error('Platform unavailable')) } ] adapters.forEach(adapter => { const fullAdapter: IPlatformAdapter = { ...adapter, request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform(adapter.platform, fullAdapter) }) const health: HealthStatus = await httpClient.getHealth() expect(health).toBeDefined() expect(health.status).toBe('degraded') // Overall status should be degraded expect(health.platforms['healthy-platform']?.status).toBe('healthy') expect(health.platforms['unhealthy-platform']?.status).toBe('unhealthy') }) }) describe('Error Handling', () => { test('should reject registration with empty platform name', () => { const adapter: IPlatformAdapter = { platform: '', baseUrl: 'https://api.test.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } expect(() => { httpClient.registerPlatform('', adapter) }).toThrow('Platform name cannot be empty') }) test('should reject registration with mismatched platform name', () => { const adapter: IPlatformAdapter = { platform: 'adapter-platform', baseUrl: 'https://api.test.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } expect(() => { httpClient.registerPlatform('different-platform', adapter) }).toThrow('Platform name mismatch') }) test('should reject registration with null or undefined adapter', () => { expect(() => { httpClient.registerPlatform('test-platform', null as any) }).toThrow('Platform adapter cannot be null or undefined') expect(() => { httpClient.registerPlatform('test-platform', undefined as any) }).toThrow('Platform adapter cannot be null or undefined') }) }) describe('Resource Cleanup', () => { test('should properly clean up resources when client is closed', async () => { const adapter: IPlatformAdapter = { platform: 'cleanup-platform', baseUrl: 'https://api.cleanup.com', request: jest.fn(), prepareRequest: jest.fn(), setProxyConfig: jest.fn(), getProxyStatus: jest.fn(), processResponse: jest.fn(), checkHealth: jest.fn(), getConfig: jest.fn(), validateConfig: jest.fn().mockReturnValue(true) } httpClient.registerPlatform('cleanup-platform', adapter) expect(httpClient.isPlatformRegistered?.('cleanup-platform')).toBe(true) await httpClient.close() // After closing, platform should still be registered but client should be inactive expect(httpClient.isPlatformRegistered?.('cleanup-platform')).toBe(true) // Attempting to make requests should fail await expect(httpClient.request({ platform: 'cleanup-platform', accountId: 'test', method: 'GET', url: '/test' })).rejects.toThrow('Client is closed') }) }) })