import { vi } from 'vitest'; import { InMemoryHealthCheckAdapter } from '../../../adapters/health/persistence/inmemory/InMemoryHealthCheckAdapter'; import { InMemoryHealthEventPublisher } from '../../../adapters/events/InMemoryHealthEventPublisher'; import { ApiConnectionMonitor } from '../../../apps/website/lib/gateways/api/base/ApiConnectionMonitor'; import { CheckApiHealthUseCase } from '../../../core/health/use-cases/CheckApiHealthUseCase'; import { GetConnectionStatusUseCase } from '../../../core/health/use-cases/GetConnectionStatusUseCase'; export class HealthTestContext { public healthCheckAdapter: InMemoryHealthCheckAdapter; public eventPublisher: InMemoryHealthEventPublisher; public apiConnectionMonitor: ApiConnectionMonitor; public checkApiHealthUseCase: CheckApiHealthUseCase; public getConnectionStatusUseCase: GetConnectionStatusUseCase; public mockFetch = vi.fn(); private constructor() { this.healthCheckAdapter = new InMemoryHealthCheckAdapter(); this.eventPublisher = new InMemoryHealthEventPublisher(); // Initialize Use Cases this.checkApiHealthUseCase = new CheckApiHealthUseCase({ healthCheckAdapter: this.healthCheckAdapter, eventPublisher: this.eventPublisher, }); this.getConnectionStatusUseCase = new GetConnectionStatusUseCase({ healthCheckAdapter: this.healthCheckAdapter, }); // Initialize Monitor (ApiConnectionMonitor as any).instance = undefined; this.apiConnectionMonitor = ApiConnectionMonitor.getInstance('/health'); // Setup global fetch mock global.fetch = this.mockFetch as any; } public static create(): HealthTestContext { return new HealthTestContext(); } public reset(): void { this.healthCheckAdapter.clear(); this.eventPublisher.clear(); this.mockFetch.mockReset(); // Reset monitor singleton (ApiConnectionMonitor as any).instance = undefined; this.apiConnectionMonitor = ApiConnectionMonitor.getInstance('/health'); // Default mock implementation for fetch to use the adapter this.mockFetch.mockImplementation(async (url: string) => { // Simulate network delay if configured in adapter const responseTime = (this.healthCheckAdapter as any).responseTime || 0; if (responseTime > 0) { await new Promise(resolve => setTimeout(resolve, responseTime)); } if ((this.healthCheckAdapter as any).shouldFail) { const error = (this.healthCheckAdapter as any).failError || 'Network Error'; if (error === 'Timeout') { // Simulate timeout by never resolving or rejecting until aborted return new Promise((_, reject) => { const timeout = setTimeout(() => reject(new Error('Timeout')), 10000); // In a real fetch, the signal would abort this }); } throw new Error(error); } return { ok: true, status: 200, json: async () => ({ status: 'ok' }), } as Response; }); // Ensure monitor starts with a clean state for each test this.apiConnectionMonitor.reset(); // Force status to checking initially as per monitor logic for 0 requests (this.apiConnectionMonitor as any).health.status = 'checking'; } public teardown(): void { this.apiConnectionMonitor.stopMonitoring(); vi.restoreAllMocks(); } }