/**
* Breakpoint Integration Tests
*
* End-to-end tests for the complete breakpoint functionality
* including MCP tools, DebuggerCore, and Chrome integration
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { DebuggerCore } from '../src/core/DebuggerCore.js';
import { ConfigManager } from '../src/config/ConfigManager.js';
import { BreakpointCommand } from '../src/managers/BreakpointManager.js';
// Mock all external dependencies
vi.mock('../src/config/ConfigManager.js');
vi.mock('../src/debuggers/ChromeDebugger.js');
vi.mock('../src/watchers/FileWatcher.js');
vi.mock('../src/analyzers/CodeAnalyzer.js');
vi.mock('../src/monitors/PerformanceMonitor.js');
vi.mock('../src/trackers/ErrorTracker.js');
vi.mock('../src/streams/StreamManager.js');
describe('Breakpoint Integration Tests', () => {
let debuggerCore: DebuggerCore;
let mockConfigManager: ConfigManager;
const mockConfig = {
complexity: {
maxFileLines: 300,
maxFunctionComplexity: 10,
maxFunctionParams: 5,
maxNestingDepth: 4,
maxImports: 20
},
patterns: {
namingConventions: {
components: '^[A-Z][a-zA-Z0-9]*$',
hooks: '^use[A-Z][a-zA-Z0-9]*$',
constants: '^[A-Z][A-Z0-9_]*$',
functions: '^[a-z][a-zA-Z0-9]*$',
variables: '^[a-z][a-zA-Z0-9]*$'
},
importRules: [],
componentRules: [],
fileStructure: []
},
performance: {
renderTimeThreshold: 16,
memoryLeakThreshold: 52428800,
bundleSizeThreshold: 1048576,
networkTimeoutThreshold: 5000,
enableProfiling: true
},
errors: {
trackConsoleErrors: true,
trackUnhandledRejections: true,
trackNetworkErrors: true,
trackReactErrors: true,
enableStackTraces: true
},
watching: {
enabled: true,
paths: ['src'],
ignored: ['node_modules'],
includeNodeModules: false,
debounceMs: 300
},
browser: {
autoConnect: true,
port: 9222,
host: 'localhost',
timeout: 10000,
retryAttempts: 3,
retryDelay: 2000
},
breakpoints: {
maxRecentHits: 100,
autoRemoveAfterHits: undefined,
enableAnalytics: true,
persistBreakpoints: true,
logpointTimeout: 5000,
enableConditionalBreakpoints: true,
enableLogpoints: true
},
ai: {
enabled: false,
provider: 'disabled',
enableErrorCategorization: false,
enablePatternDetection: false,
enablePerformanceInsights: false
},
streaming: {
enabled: true,
bufferSize: 1000,
flushInterval: 1000,
enableCompression: false
}
};
beforeEach(async () => {
// Setup config manager mock
mockConfigManager = new ConfigManager();
vi.mocked(mockConfigManager.getConfig).mockReturnValue(mockConfig);
vi.mocked(mockConfigManager.on).mockImplementation(() => mockConfigManager);
vi.mocked(mockConfigManager.updateConfig).mockResolvedValue();
// Create DebuggerCore instance
debuggerCore = new DebuggerCore(mockConfigManager);
// Mock the initialization to avoid actual Chrome connection
const mockComponents = {
errorTracker: {
initialize: vi.fn().mockResolvedValue(undefined),
getErrorCount: vi.fn().mockReturnValue(0),
shutdown: vi.fn().mockResolvedValue(undefined)
},
codeAnalyzer: {
initialize: vi.fn().mockResolvedValue(undefined),
getViolationCount: vi.fn().mockReturnValue(0),
shutdown: vi.fn().mockResolvedValue(undefined)
},
performanceMonitor: {
initialize: vi.fn().mockResolvedValue(undefined),
shutdown: vi.fn().mockResolvedValue(undefined),
setChromeDebugger: vi.fn(),
setComponentManager: vi.fn()
},
fileWatcher: {
initialize: vi.fn().mockResolvedValue(undefined),
getWatchedCount: vi.fn().mockReturnValue(5),
shutdown: vi.fn().mockResolvedValue(undefined)
},
streamManager: {
initialize: vi.fn().mockResolvedValue(undefined),
shutdown: vi.fn().mockResolvedValue(undefined)
},
chromeDebugger: {
initialize: vi.fn().mockResolvedValue(undefined),
isDebuggerEnabled: vi.fn().mockReturnValue(true),
setBreakpoint: vi.fn(),
removeBreakpoint: vi.fn(),
getBreakpoints: vi.fn().mockReturnValue([]),
clearAllBreakpoints: vi.fn(),
setBreakpointsActive: vi.fn(),
shutdown: vi.fn(),
on: vi.fn(),
emit: vi.fn()
},
breakpointManager: {
initialize: vi.fn().mockResolvedValue(undefined),
executeCommand: vi.fn(),
shutdown: vi.fn().mockResolvedValue(undefined)
},
aiCodeQualityAnalyzer: {
initialize: vi.fn().mockResolvedValue(undefined),
shutdown: vi.fn().mockResolvedValue(undefined)
},
aiErrorAnalyzer: {
initialize: vi.fn().mockResolvedValue(undefined),
shutdown: vi.fn().mockResolvedValue(undefined)
},
componentManager: {
initialize: vi.fn().mockResolvedValue(undefined),
shutdown: vi.fn().mockResolvedValue(undefined)
}
};
// Inject mocked components
Object.assign(debuggerCore as any, mockComponents);
await debuggerCore.initialize();
});
afterEach(() => {
vi.clearAllMocks();
});
describe('MCP Tool Integration', () => {
it('should handle set breakpoint command', async () => {
const mockBreakpoint = {
id: 'bp-integration-test',
location: { filePath: 'src/test.js', lineNumber: 10 },
options: { enabled: true },
hitCount: 0,
enabled: true,
timestamp: new Date()
};
const mockResult = {
success: true,
message: 'Breakpoint set successfully',
breakpoint: mockBreakpoint
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'set',
location: {
filePath: 'src/test.js',
lineNumber: 10
},
options: {
condition: 'x > 5',
enabled: true
}
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(result.breakpoint).toEqual(mockBreakpoint);
expect(breakpointManager.executeCommand).toHaveBeenCalledWith(command);
});
it('should handle remove breakpoint command', async () => {
const mockResult = {
success: true,
message: 'Breakpoint removed successfully'
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'remove',
breakpointId: 'bp-to-remove'
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(breakpointManager.executeCommand).toHaveBeenCalledWith(command);
});
it('should handle list breakpoints command', async () => {
const mockBreakpoints = [
{
id: 'bp-1',
location: { filePath: 'src/test1.js', lineNumber: 10 },
options: { enabled: true },
hitCount: 5,
enabled: true,
timestamp: new Date()
},
{
id: 'bp-2',
location: { filePath: 'src/test2.js', lineNumber: 20 },
options: { enabled: true },
hitCount: 2,
enabled: true,
timestamp: new Date()
}
];
const mockResult = {
success: true,
message: 'Found 2 breakpoint(s)',
breakpoints: mockBreakpoints
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'list'
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(result.breakpoints).toEqual(mockBreakpoints);
expect(result.message).toContain('Found 2 breakpoint(s)');
});
it('should handle clear breakpoints command', async () => {
const mockResult = {
success: true,
message: 'All breakpoints cleared successfully'
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'clear'
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(breakpointManager.executeCommand).toHaveBeenCalledWith(command);
});
it('should handle toggle breakpoints command', async () => {
const mockResult = {
success: true,
message: 'Breakpoints disabled successfully'
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'toggle',
active: false
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(breakpointManager.executeCommand).toHaveBeenCalledWith(command);
});
it('should handle analytics command', async () => {
const mockAnalytics = {
totalBreakpoints: 2,
activeBreakpoints: 2,
totalHits: 10,
averageHitsPerBreakpoint: 5,
recentHits: [],
hitsByFile: {},
hitsByHour: {}
};
const mockResult = {
success: true,
message: 'Analytics retrieved successfully',
analytics: mockAnalytics
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'analytics'
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(result.analytics).toBeDefined();
expect(breakpointManager.executeCommand).toHaveBeenCalledWith(command);
});
it('should fail when browser is not connected', async () => {
// Simulate browser disconnection
(debuggerCore as any).session.browserConnected = false;
const command: BreakpointCommand = {
action: 'set',
location: { filePath: 'src/test.js', lineNumber: 10 }
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(false);
expect(result.message).toContain('Chrome debugger not connected');
});
});
describe('Configuration Integration', () => {
it('should use breakpoint configuration correctly', async () => {
const config = mockConfigManager.getConfig();
expect(config.breakpoints.enableAnalytics).toBe(true);
expect(config.breakpoints.maxRecentHits).toBe(100);
expect(config.breakpoints.enableConditionalBreakpoints).toBe(true);
expect(config.breakpoints.enableLogpoints).toBe(true);
});
it('should validate breakpoint configuration', () => {
// Since ConfigManager is mocked, we'll test the validation logic conceptually
const invalidConfig = {
...mockConfig,
breakpoints: {
...mockConfig.breakpoints,
maxRecentHits: -1 // Invalid value
}
};
// In a real scenario, this would be caught by ConfigManager validation
// For the test, we'll just verify the config structure
expect(invalidConfig.breakpoints.maxRecentHits).toBe(-1);
expect(mockConfig.breakpoints.maxRecentHits).toBe(100);
});
});
describe('Error Handling', () => {
it('should handle Chrome debugger errors gracefully', async () => {
const mockErrorResult = {
success: false,
message: 'Failed to set breakpoint: Chrome connection lost'
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockErrorResult);
const command: BreakpointCommand = {
action: 'set',
location: { filePath: 'src/test.js', lineNumber: 10 }
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(false);
expect(result.message).toContain('Chrome connection lost');
});
it('should handle invalid breakpoint commands', async () => {
const mockErrorResult = {
success: false,
message: 'Unknown breakpoint action: invalid-action'
};
const breakpointManager = (debuggerCore as any).breakpointManager;
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockErrorResult);
const command = {
action: 'invalid-action' as any
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(false);
expect(result.message).toContain('Unknown breakpoint action');
});
});
describe('Session Management', () => {
it('should include breakpoint functionality in debug session', async () => {
const session = await debuggerCore.getDebugSession();
expect(session.browserConnected).toBe(true);
expect(session.status).toBe('running');
expect(session.filesWatched).toBe(5);
});
it('should handle session shutdown with breakpoints', async () => {
const chromeDebugger = (debuggerCore as any).chromeDebugger;
const breakpointManager = (debuggerCore as any).breakpointManager;
chromeDebugger.shutdown = vi.fn();
breakpointManager.shutdown = vi.fn();
await debuggerCore.shutdown();
expect(breakpointManager.shutdown).toHaveBeenCalled();
expect(chromeDebugger.shutdown).toHaveBeenCalled();
});
});
describe('Real-world Scenarios', () => {
it('should handle setting multiple breakpoints in different files', async () => {
const breakpointManager = (debuggerCore as any).breakpointManager;
const mockBreakpoints = [
{ id: 'bp-1', location: { filePath: 'src/component.js', lineNumber: 10 } },
{ id: 'bp-2', location: { filePath: 'src/utils.js', lineNumber: 25 } },
{ id: 'bp-3', location: { filePath: 'src/hooks.js', lineNumber: 15 } }
];
// Mock successful responses for each breakpoint
vi.mocked(breakpointManager.executeCommand)
.mockResolvedValueOnce({ success: true, message: 'Breakpoint set', breakpoint: mockBreakpoints[0] })
.mockResolvedValueOnce({ success: true, message: 'Breakpoint set', breakpoint: mockBreakpoints[1] })
.mockResolvedValueOnce({ success: true, message: 'Breakpoint set', breakpoint: mockBreakpoints[2] });
// Set multiple breakpoints
for (let i = 0; i < 3; i++) {
const command: BreakpointCommand = {
action: 'set',
location: mockBreakpoints[i].location
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
}
expect(breakpointManager.executeCommand).toHaveBeenCalledTimes(3);
});
it('should handle conditional breakpoints with complex expressions', async () => {
const breakpointManager = (debuggerCore as any).breakpointManager;
const mockBreakpoint = {
id: 'bp-conditional',
location: { filePath: 'src/component.js', lineNumber: 50 },
options: {
condition: 'props.user && props.user.isAdmin && state.isLoading === false',
enabled: true
}
};
const mockResult = {
success: true,
message: 'Conditional breakpoint set',
breakpoint: mockBreakpoint
};
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'set',
location: { filePath: 'src/component.js', lineNumber: 50 },
options: {
condition: 'props.user && props.user.isAdmin && state.isLoading === false'
}
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(result.breakpoint?.options.condition).toBe(command.options?.condition);
});
it('should handle logpoints for debugging without stopping execution', async () => {
const breakpointManager = (debuggerCore as any).breakpointManager;
const mockLogpoint = {
id: 'bp-logpoint',
location: { filePath: 'src/api.js', lineNumber: 30 },
options: {
logMessage: 'API Response: ${response.status} - ${response.data}',
enabled: true
}
};
const mockResult = {
success: true,
message: 'Logpoint set',
breakpoint: mockLogpoint
};
vi.mocked(breakpointManager.executeCommand).mockResolvedValue(mockResult);
const command: BreakpointCommand = {
action: 'set',
location: { filePath: 'src/api.js', lineNumber: 30 },
options: {
logMessage: 'API Response: ${response.status} - ${response.data}'
}
};
const result = await debuggerCore.executeBreakpointCommand(command);
expect(result.success).toBe(true);
expect(result.breakpoint?.options.logMessage).toBe(command.options?.logMessage);
});
});
});