/**
* Performance Monitoring End-to-End Tests
* Tests the complete performance monitoring system with real applications
*/
import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
import { DebuggerCore } from '../src/core/DebuggerCore.js';
import { ConfigManager } from '../src/config/ConfigManager.js';
import { spawn, ChildProcess } from 'child_process';
import { promises as fs } from 'fs';
import path from 'path';
describe('Performance Monitoring E2E Tests', () => {
let debuggerCore: DebuggerCore;
let configManager: ConfigManager;
let testAppProcess: ChildProcess | null = null;
let testAppPort = 3001;
beforeAll(async () => {
// Create a simple test React application for performance testing
await createTestApplication();
// Start the test application
testAppProcess = await startTestApplication();
// Wait for the application to start
await new Promise(resolve => setTimeout(resolve, 5000));
});
afterAll(async () => {
// Clean up test application
if (testAppProcess) {
testAppProcess.kill();
}
await cleanupTestApplication();
});
beforeEach(async () => {
configManager = new ConfigManager();
await configManager.initialize();
debuggerCore = new DebuggerCore(configManager);
await debuggerCore.initialize();
});
afterEach(async () => {
await debuggerCore.shutdown();
});
describe('Real Application Performance Monitoring', () => {
it('should monitor CPU performance during application load', async () => {
// Start CPU profiling
const profileId = await debuggerCore.startCPUProfiling('app-load-test');
// Simulate application interaction
await simulateApplicationLoad();
// Stop profiling and analyze
const profile = await debuggerCore.stopCPUProfiling(profileId);
expect(profile).toMatchObject({
id: profileId,
duration: expect.any(Number),
flameGraph: expect.any(Array)
});
expect(profile.duration).toBeGreaterThan(0);
expect(profile.flameGraph.length).toBeGreaterThan(0);
});
it('should detect memory leaks during extended usage', async () => {
// Take initial memory snapshot
const initialSnapshot = await debuggerCore.takeDetailedHeapSnapshot();
// Start heap sampling
await debuggerCore.startHeapSampling(16384);
// Simulate memory-intensive operations
await simulateMemoryIntensiveOperations();
// Stop heap sampling
const heapProfile = await debuggerCore.stopHeapSampling();
// Take final memory snapshot
const finalSnapshot = await debuggerCore.takeDetailedHeapSnapshot();
expect(heapProfile.samples).toBeDefined();
expect(Array.isArray(heapProfile.samples)).toBe(true);
// Analyze memory growth
const memorySnapshots = await debuggerCore.getMemorySnapshots(10);
expect(memorySnapshots.length).toBeGreaterThan(0);
// Check for memory alerts
const alerts = await debuggerCore.getPerformanceAlerts(false);
const memoryAlerts = alerts.filter((a: any) => a.type === 'memory');
// Memory alerts might be generated if there's significant growth
expect(Array.isArray(memoryAlerts)).toBe(true);
});
it('should monitor network performance during API calls', async () => {
// Simulate network requests
await simulateNetworkRequests();
// Wait for network metrics to be collected
await new Promise(resolve => setTimeout(resolve, 2000));
// Analyze network performance
const networkAnalysis = await debuggerCore.analyzeNetworkPerformance(60000);
expect(networkAnalysis).toMatchObject({
totalRequests: expect.any(Number),
averageResponseTime: expect.any(Number),
slowRequests: expect.any(Array),
failedRequests: expect.any(Number),
domainBreakdown: expect.any(Object),
recommendations: expect.any(Array)
});
// Should have captured some network activity
expect(networkAnalysis.totalRequests).toBeGreaterThanOrEqual(0);
});
it('should track React component render performance', async () => {
// Simulate component interactions
await simulateComponentInteractions();
// Analyze render performance
const renderAnalysis = await debuggerCore.analyzeRenderPerformance(60000);
expect(renderAnalysis).toMatchObject({
totalRenders: expect.any(Number),
averageRenderTime: expect.any(Number),
slowRenders: expect.any(Array),
rendersByComponent: expect.any(Object),
renderReasons: expect.any(Object),
recommendations: expect.any(Array),
performanceScore: expect.any(Number)
});
expect(renderAnalysis.performanceScore).toBeGreaterThanOrEqual(0);
expect(renderAnalysis.performanceScore).toBeLessThanOrEqual(100);
});
it('should generate comprehensive performance recommendations', async () => {
// Perform various operations to generate performance data
await Promise.all([
simulateApplicationLoad(),
simulateNetworkRequests(),
simulateComponentInteractions()
]);
// Wait for data collection
await new Promise(resolve => setTimeout(resolve, 3000));
// Get comprehensive recommendations
const recommendations = await debuggerCore.getPerformanceOptimizationRecommendations(300000);
expect(recommendations).toMatchObject({
overallScore: expect.any(Number),
categories: {
render: expect.objectContaining({
score: expect.any(Number),
issues: expect.any(Array),
recommendations: expect.any(Array)
}),
network: expect.objectContaining({
score: expect.any(Number),
issues: expect.any(Array),
recommendations: expect.any(Array)
}),
memory: expect.objectContaining({
score: expect.any(Number),
issues: expect.any(Array),
recommendations: expect.any(Array)
}),
cpu: expect.objectContaining({
score: expect.any(Number),
issues: expect.any(Array),
recommendations: expect.any(Array)
})
},
prioritizedActions: expect.any(Array),
quickWins: expect.any(Array),
longTermGoals: expect.any(Array)
});
// Validate score ranges
expect(recommendations.overallScore).toBeGreaterThanOrEqual(0);
expect(recommendations.overallScore).toBeLessThanOrEqual(100);
// Should have some recommendations
expect(recommendations.quickWins.length).toBeGreaterThanOrEqual(0);
expect(recommendations.longTermGoals.length).toBeGreaterThan(0);
});
});
describe('Performance Monitoring Under Load', () => {
it('should handle high-frequency render tracking', async () => {
// Simulate rapid component renders
const renderPromises = [];
for (let i = 0; i < 50; i++) {
renderPromises.push(
debuggerCore.startRenderTracking(`component-${i}`, 'props', [`prop-${i}`], [])
.then(() => new Promise(resolve => setTimeout(resolve, Math.random() * 10)))
.then(() => debuggerCore.trackComponentRender(`component-${i}`, 'props', [`prop-${i}`], []))
);
}
await Promise.all(renderPromises);
// Analyze the results
const renderAnalysis = await debuggerCore.analyzeRenderPerformance(60000);
expect(renderAnalysis.totalRenders).toBeGreaterThanOrEqual(50);
});
it('should maintain performance under concurrent monitoring', async () => {
const startTime = Date.now();
// Run multiple monitoring operations concurrently
const operations = [
debuggerCore.getPerformanceMetrics({ limit: 100 }),
debuggerCore.analyzeNetworkPerformance(60000),
debuggerCore.analyzeRenderPerformance(60000),
debuggerCore.getMemorySnapshots(20),
debuggerCore.getPerformanceAlerts(),
debuggerCore.getDetailedRenderMetrics()
];
const results = await Promise.all(operations);
const endTime = Date.now();
// All operations should complete
expect(results).toHaveLength(6);
results.forEach(result => expect(result).toBeDefined());
// Should complete in reasonable time (under 5 seconds)
expect(endTime - startTime).toBeLessThan(5000);
});
});
// Helper functions for test application simulation
async function createTestApplication(): Promise<void> {
const testAppDir = path.join(process.cwd(), 'test-performance-app');
try {
await fs.mkdir(testAppDir, { recursive: true });
// Create a simple React app with performance issues for testing
const packageJson = {
name: 'test-performance-app',
version: '1.0.0',
scripts: {
start: 'react-scripts start',
build: 'react-scripts build'
},
dependencies: {
react: '^18.0.0',
'react-dom': '^18.0.0',
'react-scripts': '^5.0.0'
},
browserslist: {
production: ['>0.2%', 'not dead', 'not op_mini all'],
development: ['last 1 chrome version', 'last 1 firefox version', 'last 1 safari version']
}
};
await fs.writeFile(
path.join(testAppDir, 'package.json'),
JSON.stringify(packageJson, null, 2)
);
// Create public/index.html
await fs.mkdir(path.join(testAppDir, 'public'), { recursive: true });
const indexHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Performance Test App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>`;
await fs.writeFile(path.join(testAppDir, 'public', 'index.html'), indexHtml);
// Create src/index.js
await fs.mkdir(path.join(testAppDir, 'src'), { recursive: true });
const indexJs = `import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);`;
await fs.writeFile(path.join(testAppDir, 'src', 'index.js'), indexJs);
// Create src/App.js with intentional performance issues
const appJs = `import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
const [data, setData] = useState([]);
// Intentionally inefficient effect
useEffect(() => {
const interval = setInterval(() => {
setCount(c => c + 1);
}, 100);
return () => clearInterval(interval);
}, []);
// Intentionally heavy computation
const heavyComputation = () => {
let result = 0;
for (let i = 0; i < 100000; i++) {
result += Math.random();
}
return result;
};
return (
<div>
<h1>Performance Test App</h1>
<p>Count: {count}</p>
<p>Heavy computation result: {heavyComputation()}</p>
<button onClick={() => setData([...data, Date.now()])}>
Add Data ({data.length} items)
</button>
{data.map((item, index) => (
<div key={index}>Item {index}: {item}</div>
))}
</div>
);
}
export default App;`;
await fs.writeFile(path.join(testAppDir, 'src', 'App.js'), appJs);
} catch (error) {
console.warn('Could not create test application:', error);
}
}
async function startTestApplication(): Promise<ChildProcess> {
return new Promise((resolve, reject) => {
const testAppDir = path.join(process.cwd(), 'test-performance-app');
// Start the React app
const process = spawn('npm', ['start'], {
cwd: testAppDir,
env: { ...process.env, PORT: testAppPort.toString() },
stdio: 'pipe'
});
process.stdout?.on('data', (data) => {
if (data.toString().includes('webpack compiled')) {
resolve(process);
}
});
process.stderr?.on('data', (data) => {
console.warn('Test app stderr:', data.toString());
});
process.on('error', reject);
// Timeout after 30 seconds
setTimeout(() => {
reject(new Error('Test application failed to start within 30 seconds'));
}, 30000);
});
}
async function cleanupTestApplication(): Promise<void> {
try {
const testAppDir = path.join(process.cwd(), 'test-performance-app');
await fs.rm(testAppDir, { recursive: true, force: true });
} catch (error) {
console.warn('Could not clean up test application:', error);
}
}
async function simulateApplicationLoad(): Promise<void> {
// Simulate loading the application
await new Promise(resolve => setTimeout(resolve, 1000));
}
async function simulateMemoryIntensiveOperations(): Promise<void> {
// Simulate memory-intensive operations
await new Promise(resolve => setTimeout(resolve, 2000));
}
async function simulateNetworkRequests(): Promise<void> {
// Simulate network requests
await new Promise(resolve => setTimeout(resolve, 1500));
}
async function simulateComponentInteractions(): Promise<void> {
// Simulate component interactions
await new Promise(resolve => setTimeout(resolve, 1000));
}
});