// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= import { setupElectronMocks, TestScenarios } from './electronMocks'; import { setupMockEnvironment } from './environmentMocks'; /** * Complete test setup utility that combines all mocks and provides * easy-to-use functions for testing installation flows */ export function createTestEnvironment() { const { electronAPI, ipcRenderer } = setupElectronMocks(); const mockEnv = setupMockEnvironment(); return { electronAPI, ipcRenderer, mockEnv, // Quick scenario setups scenarios: { /** * Fresh installation - no .venv, no version file, tools not installed */ freshInstall: () => { TestScenarios.freshInstall(electronAPI); mockEnv.scenarios.freshInstall(); }, /** * Version update - version file exists but version changed */ versionUpdate: ( oldVersion: string = '0.9.0', newVersion: string = '1.0.0' ) => { TestScenarios.versionUpdate(electronAPI); mockEnv.scenarios.versionUpdate(oldVersion, newVersion); }, /** * .venv removed - version file exists but .venv is missing */ venvRemoved: () => { TestScenarios.venvRemoved(electronAPI); mockEnv.scenarios.venvRemoved(); }, /** * Installation in progress - when user opens app during installation */ installationInProgress: () => { TestScenarios.installationInProgress(electronAPI); mockEnv.scenarios.installationInProgress(); }, /** * Installation error - installation fails */ installationError: () => { TestScenarios.installationError(electronAPI); mockEnv.scenarios.completeFailure(); }, /** * Uvicorn startup with dependency installation */ uvicornDepsInstall: () => { TestScenarios.uvicornDepsInstall(electronAPI); mockEnv.scenarios.uvicornStartupInstall(); }, /** * Network issues - default mirror fails, backup succeeds */ networkIssues: () => { TestScenarios.allGood(electronAPI); mockEnv.scenarios.networkIssues(); }, /** * All good - no installation needed */ allGood: () => { TestScenarios.allGood(electronAPI); // Use default mockEnv state (all good) }, }, // Simulation utilities simulate: { /** * Simulate a complete successful installation flow */ successfulInstallation: async (delay: number = 100) => { electronAPI.simulateInstallationStart(); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Resolving dependencies...' ); }, delay); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Downloading packages...' ); }, delay * 2); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Installing packages...' ); }, delay * 3); setTimeout(() => { electronAPI.simulateInstallationComplete(true); }, delay * 4); }, /** * Simulate a failed installation flow */ failedInstallation: async ( delay: number = 100, errorMessage: string = 'Installation failed' ) => { electronAPI.simulateInstallationStart(); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Resolving dependencies...' ); }, delay); setTimeout(() => { electronAPI.simulateInstallationLog( 'stderr', `Error: ${errorMessage}` ); }, delay * 2); setTimeout(() => { electronAPI.simulateInstallationComplete(false, errorMessage); }, delay * 3); }, /** * Simulate uvicorn startup that detects missing dependencies */ uvicornWithDeps: async (delay: number = 100) => { setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Uvicorn detected missing dependencies' ); }, delay); setTimeout(() => { electronAPI.simulateInstallationStart(); }, delay * 2); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Resolving dependencies...' ); }, delay * 3); setTimeout(() => { electronAPI.simulateInstallationLog( 'stdout', 'Uvicorn running on http://127.0.0.1:8000' ); electronAPI.simulateInstallationComplete(true); }, delay * 4); }, }, // State inspection utilities inspect: { /** * Get current installation state summary */ getInstallationState: () => ({ electronState: electronAPI.mockState, envState: mockEnv.mockState, isInstalling: electronAPI.mockState.isInstalling || mockEnv.mockState.processes.installationInProgress, hasLockFiles: mockEnv.mockState.filesystem.installingLockExists || mockEnv.mockState.filesystem.installedLockExists, toolsAvailable: mockEnv.mockState.processes.uvAvailable && mockEnv.mockState.processes.bunAvailable, venvExists: electronAPI.mockState.venvExists && mockEnv.mockState.filesystem.venvExists, }), /** * Check if environment is in expected state for a scenario */ verifyScenario: (scenarioName: string) => { const state = mockEnv.mockState; const electronState = electronAPI.mockState; switch (scenarioName) { case 'freshInstall': return ( !state.filesystem.venvExists && !state.filesystem.versionFileExists && !electronState.toolInstalled ); case 'versionUpdate': return ( state.filesystem.versionFileExists && state.app.currentVersion !== state.filesystem.versionFileContent ); case 'venvRemoved': return ( !state.filesystem.venvExists && state.filesystem.versionFileExists ); case 'installationInProgress': return ( state.filesystem.installingLockExists || electronState.isInstalling ); default: return false; } }, }, // Reset everything reset: () => { electronAPI.reset(); mockEnv.reset(); }, }; } /** * Helper function to wait for installation state changes */ export async function waitForInstallationState( getState: () => any, expectedState: string, timeout: number = 1000 ): Promise { return new Promise((resolve, reject) => { const startTime = Date.now(); const check = () => { if (getState().state === expectedState) { resolve(); } else if (Date.now() - startTime > timeout) { reject( new Error( `Timeout waiting for state ${expectedState}, current: ${getState().state}` ) ); } else { setTimeout(check, 10); } }; check(); }); } /** * Helper function to wait for multiple logs */ export async function waitForLogs( getLogs: () => any[], expectedCount: number, timeout: number = 1000 ): Promise { return new Promise((resolve, reject) => { const startTime = Date.now(); const check = () => { if (getLogs().length >= expectedCount) { resolve(); } else if (Date.now() - startTime > timeout) { reject( new Error( `Timeout waiting for ${expectedCount} logs, got: ${getLogs().length}` ) ); } else { setTimeout(check, 10); } }; check(); }); } /** * Example usage in tests: * * ```typescript * import { createTestEnvironment, waitForInstallationState } from '../mocks/testUtils' * * describe('Installation Flow', () => { * let testEnv: ReturnType * * beforeEach(() => { * testEnv = createTestEnvironment() * }) * * it('should handle fresh installation', async () => { * testEnv.scenarios.freshInstall() * * // Verify scenario setup * expect(testEnv.inspect.verifyScenario('freshInstall')).toBe(true) * * // Simulate installation * await testEnv.simulate.successfulInstallation() * * // Verify result * const state = testEnv.inspect.getInstallationState() * expect(state.isInstalling).toBe(false) * }) * }) * ``` */