@clduab11/gemini-flow
Version:
Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.
535 lines (442 loc) • 20.7 kB
text/typescript
/**
* Execute Command Tests
*
* Comprehensive tests for the execute command functionality
*/
import { describe, test, expect, beforeEach, afterEach, jest } from '@jest/globals';
import { ExecuteCommand } from '../../gemini-flow/src/cli/commands/execute';
import { ConfigManager } from '../../gemini-flow/src/cli/config/config-manager';
import { Logger } from '../../gemini-flow/src/utils/logger';
import { writeFile, mkdir, rmdir } from 'fs/promises';
import { join } from 'path';
import { tmpdir } from 'os';
// Mock external dependencies
jest.mock('../../gemini-flow/src/utils/logger');
jest.mock('../../gemini-flow/src/core/model-orchestrator');
jest.mock('../../gemini-flow/src/adapters/gemini-adapter');
describe('ExecuteCommand', () => {
let executeCommand: ExecuteCommand;
let configManager: ConfigManager;
let testDir: string;
beforeEach(async () => {
// Create temporary test directory
testDir = join(tmpdir(), `gemini-flow-test-${Date.now()}`);
await mkdir(testDir, { recursive: true });
// Initialize command
configManager = new ConfigManager();
executeCommand = new ExecuteCommand(configManager);
// Change to test directory
process.chdir(testDir);
});
afterEach(async () => {
// Cleanup test directory
try {
await rmdir(testDir, { recursive: true });
} catch (error) {
// Ignore cleanup errors
}
});
describe('Framework Detection', () => {
test('should detect FastAPI framework', async () => {
// Create FastAPI project structure
await writeFile(join(testDir, 'main.py'), 'from fastapi import FastAPI\napp = FastAPI()');
await writeFile(join(testDir, 'requirements.txt'), 'fastapi\nuvicorn');
// Test framework detection
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('fastapi');
});
test('should detect Next.js framework', async () => {
// Create Next.js project structure
await writeFile(join(testDir, 'next.config.js'), 'module.exports = {}');
await writeFile(join(testDir, 'package.json'), JSON.stringify({
name: 'test-app',
dependencies: { 'next': '^13.0.0' }
}));
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('nextjs');
});
test('should detect React framework', async () => {
await mkdir(join(testDir, 'src'), { recursive: true });
await writeFile(join(testDir, 'src', 'App.js'), 'import React from "react";');
await writeFile(join(testDir, 'package.json'), JSON.stringify({
name: 'test-app',
dependencies: { 'react': '^18.0.0' }
}));
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('react');
});
test('should detect Express framework', async () => {
await writeFile(join(testDir, 'server.js'), 'const express = require("express");');
await writeFile(join(testDir, 'package.json'), JSON.stringify({
name: 'test-app',
dependencies: { 'express': '^4.18.0' }
}));
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('express');
});
test('should detect Django framework', async () => {
await writeFile(join(testDir, 'manage.py'), '#!/usr/bin/env python');
await writeFile(join(testDir, 'settings.py'), 'DEBUG = True');
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('django');
});
});
describe('Test Framework Detection', () => {
test('should detect pytest', async () => {
await mkdir(join(testDir, 'tests'), { recursive: true });
await writeFile(join(testDir, 'tests', 'test_main.py'), 'def test_example(): pass');
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.testFramework).toBe('pytest');
});
test('should detect Jest', async () => {
await writeFile(join(testDir, 'app.test.js'), 'test("example", () => {});');
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.testFramework).toBe('jest');
});
});
describe('Dependency Analysis', () => {
test('should parse Python requirements.txt', async () => {
await writeFile(join(testDir, 'requirements.txt'), 'fastapi==0.104.1\nuvicorn[standard]>=0.24.0\npydantic>=2.0.0');
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'fastapi' });
expect(context.dependencies).toContain('fastapi==0.104.1');
expect(context.dependencies).toContain('uvicorn[standard]>=0.24.0');
expect(context.dependencies).toContain('pydantic>=2.0.0');
});
test('should parse package.json dependencies', async () => {
const packageJson = {
name: 'test-app',
dependencies: {
'express': '^4.18.0',
'cors': '^2.8.5'
},
devDependencies: {
'nodemon': '^3.0.0'
}
};
await writeFile(join(testDir, 'package.json'), JSON.stringify(packageJson, null, 2));
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'express' });
expect(context.dependencies).toContain('express');
expect(context.dependencies).toContain('cors');
expect(context.dependencies).toContain('nodemon');
});
test('should parse pyproject.toml dependencies', async () => {
const pyprojectToml = `[project]
dependencies = [
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0"
]`;
await writeFile(join(testDir, 'pyproject.toml'), pyprojectToml);
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'fastapi' });
expect(context.dependencies).toContain('fastapi>=0.104.0');
expect(context.dependencies).toContain('uvicorn[standard]>=0.24.0');
});
});
describe('File Scanning', () => {
test('should scan Python files for FastAPI project', async () => {
await writeFile(join(testDir, 'main.py'), 'from fastapi import FastAPI');
await writeFile(join(testDir, 'models.py'), 'from pydantic import BaseModel');
await mkdir(join(testDir, 'routers'), { recursive: true });
await writeFile(join(testDir, 'routers', 'users.py'), 'from fastapi import APIRouter');
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'fastapi' });
const pyFiles = context.files.filter((f: string) => f.endsWith('.py'));
expect(pyFiles.length).toBeGreaterThan(0);
expect(pyFiles.some((f: string) => f.includes('main.py'))).toBe(true);
expect(pyFiles.some((f: string) => f.includes('models.py'))).toBe(true);
expect(pyFiles.some((f: string) => f.includes('users.py'))).toBe(true);
});
test('should scan JavaScript/TypeScript files for React project', async () => {
await mkdir(join(testDir, 'src'), { recursive: true });
await writeFile(join(testDir, 'src', 'App.js'), 'import React from "react";');
await writeFile(join(testDir, 'src', 'index.js'), 'import ReactDOM from "react-dom";');
await mkdir(join(testDir, 'src', 'components'), { recursive: true });
await writeFile(join(testDir, 'src', 'components', 'Header.tsx'), 'export const Header = () => {};');
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'react' });
const jsFiles = context.files.filter((f: string) => f.match(/\.(js|jsx|ts|tsx)$/));
expect(jsFiles.length).toBeGreaterThan(0);
expect(jsFiles.some((f: string) => f.includes('App.js'))).toBe(true);
expect(jsFiles.some((f: string) => f.includes('Header.tsx'))).toBe(true);
});
test('should ignore node_modules and hidden directories', async () => {
await mkdir(join(testDir, 'node_modules'), { recursive: true });
await writeFile(join(testDir, 'node_modules', 'package.js'), 'module.exports = {};');
await mkdir(join(testDir, '.git'), { recursive: true });
await writeFile(join(testDir, '.git', 'config'), '[core]');
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'react' });
expect(context.files.some((f: string) => f.includes('node_modules'))).toBe(false);
expect(context.files.some((f: string) => f.includes('.git'))).toBe(false);
});
});
describe('Environment Setup', () => {
test('should set FastAPI environment variables', async () => {
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'fastapi' });
expect(context.environment.PYTHONPATH).toBe(process.cwd());
expect(context.environment.FASTAPI_ENV).toBe('development');
});
test('should set Next.js environment variables', async () => {
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'nextjs' });
expect(context.environment.NODE_ENV).toBe('development');
expect(context.environment.NEXT_TELEMETRY_DISABLED).toBe('1');
});
test('should set React environment variables', async () => {
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'react' });
expect(context.environment.NODE_ENV).toBe('development');
expect(context.environment.REACT_APP_NODE_ENV).toBe('development');
});
test('should set Django environment variables', async () => {
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'django' });
expect(context.environment.DJANGO_SETTINGS_MODULE).toBe('settings');
expect(context.environment.PYTHONPATH).toBe(process.cwd());
});
});
describe('Execution Commands', () => {
test('should generate correct FastAPI execution command', () => {
const context = {
framework: 'fastapi',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getExecutionCommand(context);
expect(command.cmd).toBe('uvicorn');
expect(command.args).toEqual(['main:app', '--reload']);
});
test('should generate correct Next.js execution command', () => {
const context = {
framework: 'nextjs',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getExecutionCommand(context);
expect(command.cmd).toBe('npm');
expect(command.args).toEqual(['run', 'dev']);
});
test('should generate correct Django execution command', () => {
const context = {
framework: 'django',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getExecutionCommand(context);
expect(command.cmd).toBe('python');
expect(command.args).toEqual(['manage.py', 'runserver']);
});
test('should generate correct Express execution command', () => {
const context = {
framework: 'express',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getExecutionCommand(context);
expect(command.cmd).toBe('node');
expect(command.args).toEqual(['server.js']);
});
});
describe('Test Commands', () => {
test('should generate correct pytest command', () => {
const context = {
testFramework: 'pytest',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getTestCommand(context);
expect(command.cmd).toBe('pytest');
expect(command.args).toEqual(['--cov=.', '--cov-report=term-missing']);
});
test('should generate correct Jest command', () => {
const context = {
testFramework: 'jest',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getTestCommand(context);
expect(command.cmd).toBe('npm');
expect(command.args).toEqual(['test', '--coverage']);
});
test('should generate correct Mocha command', () => {
const context = {
testFramework: 'mocha',
workingDirectory: testDir,
environment: {}
};
const command = (executeCommand as any).getTestCommand(context);
expect(command.cmd).toBe('nyc');
expect(command.args).toEqual(['mocha']);
});
});
describe('Coverage Extraction', () => {
test('should extract pytest coverage percentage', () => {
const output = `
========================= test session starts =========================
collected 10 items
tests/test_main.py .......... [100%]
---------- coverage: platform linux, python 3.9.18-final-0 ----------
Name Stmts Miss Cover Missing
--------------------------------------------------
main.py 25 2 92% 45-46
models.py 15 0 100%
--------------------------------------------------
TOTAL 40 2 95%
`;
const coverage = (executeCommand as any).extractCoverage(output, 'pytest');
expect(coverage).toBe(95);
});
test('should extract Jest coverage percentage', () => {
const output = `
PASS src/App.test.js
✓ renders learn react link (23ms)
----------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------------|---------|----------|---------|---------|-------------------
All files | 88.24 | 75.00 | 85.71 | 87.50 |
src | 88.24 | 75.00 | 85.71 | 87.50 |
App.js | 100.00| 100.00 | 100.00| 100.00|
index.js | 85.71 | 50.00 | 85.71 | 83.33 | 7,12
----------------------|---------|----------|---------|---------|-------------------
`;
const coverage = (executeCommand as any).extractCoverage(output, 'jest');
expect(coverage).toBe(88.24);
});
test('should return 0 for unknown test framework', () => {
const output = 'Some test output';
const coverage = (executeCommand as any).extractCoverage(output, 'unknown');
expect(coverage).toBe(0);
});
test('should return 0 when no coverage pattern matches', () => {
const output = 'Tests passed but no coverage info';
const coverage = (executeCommand as any).extractCoverage(output, 'pytest');
expect(coverage).toBe(0);
});
});
describe('File Type Detection', () => {
test('should identify relevant Python files for FastAPI', () => {
expect((executeCommand as any).isRelevantFile('main.py', '.py', 'fastapi')).toBe(true);
expect((executeCommand as any).isRelevantFile('models.py', '.py', 'fastapi')).toBe(true);
expect((executeCommand as any).isRelevantFile('requirements.txt', '.txt', 'fastapi')).toBe(true);
expect((executeCommand as any).isRelevantFile('config.yaml', '.yaml', 'fastapi')).toBe(true);
});
test('should identify relevant JavaScript/TypeScript files for React', () => {
expect((executeCommand as any).isRelevantFile('App.js', '.js', 'react')).toBe(true);
expect((executeCommand as any).isRelevantFile('Component.jsx', '.jsx', 'react')).toBe(true);
expect((executeCommand as any).isRelevantFile('App.ts', '.ts', 'react')).toBe(true);
expect((executeCommand as any).isRelevantFile('Component.tsx', '.tsx', 'react')).toBe(true);
expect((executeCommand as any).isRelevantFile('package.json', '.json', 'react')).toBe(true);
});
test('should reject irrelevant files', () => {
expect((executeCommand as any).isRelevantFile('data.csv', '.csv', 'fastapi')).toBe(false);
expect((executeCommand as any).isRelevantFile('image.png', '.png', 'react')).toBe(false);
});
});
describe('Error Handling', () => {
test('should handle missing framework gracefully', async () => {
// Create empty directory with no recognizable framework files
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBeTruthy(); // Should fallback to user selection or default
});
test('should handle missing dependencies file gracefully', async () => {
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'fastapi' });
expect(context.dependencies).toEqual([]); // Should return empty array
});
test('should handle invalid JSON in package.json gracefully', async () => {
await writeFile(join(testDir, 'package.json'), '{ invalid json }');
const context = await (executeCommand as any).analyzeExecutionContext(undefined, { framework: 'react' });
expect(context.dependencies).toEqual([]); // Should return empty array
});
});
describe('Integration Tests', () => {
test('should handle complete FastAPI project analysis', async () => {
// Create a complete FastAPI project structure
await writeFile(join(testDir, 'main.py'), `
from fastapi import FastAPI
from routers import users
app = FastAPI()
app.include_router(users.router)
`);
await writeFile(join(testDir, 'requirements.txt'), `
fastapi>=0.104.0
uvicorn[standard]>=0.24.0
pydantic>=2.0.0
pytest>=7.4.0
`);
await mkdir(join(testDir, 'routers'), { recursive: true });
await writeFile(join(testDir, 'routers', '__init__.py'), '');
await writeFile(join(testDir, 'routers', 'users.py'), `
from fastapi import APIRouter
router = APIRouter()
@router.get("/users")
async def get_users():
return {"users": []}
`);
await mkdir(join(testDir, 'tests'), { recursive: true });
await writeFile(join(testDir, 'tests', 'test_main.py'), `
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_users():
response = client.get("/users")
assert response.status_code == 200
`);
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('fastapi');
expect(context.testFramework).toBe('pytest');
expect(context.dependencies.length).toBeGreaterThan(0);
expect(context.files.length).toBeGreaterThan(0);
expect(context.environment.PYTHONPATH).toBe(process.cwd());
});
test('should handle complete React project analysis', async () => {
// Create a complete React project structure
await writeFile(join(testDir, 'package.json'), JSON.stringify({
name: 'test-react-app',
version: '1.0.0',
dependencies: {
'react': '^18.2.0',
'react-dom': '^18.2.0'
},
devDependencies: {
'@testing-library/react': '^13.4.0',
'@testing-library/jest-dom': '^5.16.5'
},
scripts: {
'start': 'react-scripts start',
'test': 'react-scripts test'
}
}, null, 2));
await mkdir(join(testDir, 'src'), { recursive: true });
await writeFile(join(testDir, 'src', 'App.js'), `
import React from 'react';
import './App.css';
function App() {
return <div className="App">Hello World</div>;
}
export default App;
`);
await writeFile(join(testDir, 'src', 'App.test.js'), `
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders hello world', () => {
render(<App />);
const linkElement = screen.getByText(/hello world/i);
expect(linkElement).toBeInTheDocument();
});
`);
await mkdir(join(testDir, 'public'), { recursive: true });
await writeFile(join(testDir, 'public', 'index.html'), `
<!DOCTYPE html>
<html lang="en">
<head>
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
`);
const context = await (executeCommand as any).analyzeExecutionContext();
expect(context.framework).toBe('react');
expect(context.testFramework).toBe('jest');
expect(context.dependencies).toContain('react');
expect(context.dependencies).toContain('react-dom');
expect(context.files.some((f: string) => f.includes('App.js'))).toBe(true);
expect(context.environment.NODE_ENV).toBe('development');
expect(context.environment.REACT_APP_NODE_ENV).toBe('development');
});
});
});