UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

251 lines (240 loc) 10.6 kB
import { BaseToolHandler } from './base-handler.js'; export class MaintenanceHandler extends BaseToolHandler { maintenanceEngine; tools = [ { name: 'analyze_test_health', description: 'Analyze the health of your test suite and identify issues', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'The debug session ID' }, testCode: { type: 'string', description: 'The test code to analyze' } }, required: ['sessionId', 'testCode'] } }, { name: 'detect_stale_tests', description: 'Detect stale selectors and outdated test code', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'The debug session ID' }, testCode: { type: 'string', description: 'The test code to check for staleness' } }, required: ['sessionId', 'testCode'] } }, { name: 'auto_fix_tests', description: 'Automatically fix simple test issues like outdated selectors', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'The debug session ID' }, testCode: { type: 'string', description: 'The test code to fix' } }, required: ['sessionId', 'testCode'] } }, { name: 'find_test_coverage_gaps', description: 'Find UI elements that are not covered by tests', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'The debug session ID' }, testSelectors: { type: 'array', items: { type: 'string' }, description: 'List of selectors used in current tests' } }, required: ['sessionId', 'testSelectors'] } }, { name: 'generate_test_maintenance_report', description: 'Generate a comprehensive test maintenance report', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'The debug session ID' }, testSuiteId: { type: 'string', description: 'Identifier for the test suite' } }, required: ['sessionId', 'testSuiteId'] } } ]; constructor(maintenanceEngine) { super(); this.maintenanceEngine = maintenanceEngine; } getTools() { return this.tools; } async handle(toolName, args, sessions) { try { const session = this.getSession(args.sessionId, sessions); switch (toolName) { case 'analyze_test_health': return await this.analyzeTestHealth(args, session); case 'detect_stale_tests': return await this.detectStaleTests(args, session); case 'auto_fix_tests': return await this.autoFixTests(args, session); case 'find_test_coverage_gaps': return await this.findCoverageGaps(args, session); case 'generate_test_maintenance_report': return await this.generateMaintenanceReport(args, session); default: return this.createErrorResponse(`Unknown tool: ${toolName}`); } } catch (error) { return this.createErrorResponse(error instanceof Error ? error.message : 'Unknown error occurred'); } } async analyzeTestHealth(args, session) { try { const staleSelectors = await this.maintenanceEngine.detectStaleSelectors(args.testCode, session.page); const elementChanges = await this.maintenanceEngine.detectElementChanges(args.testCode, session.page); const removedFeatures = await this.maintenanceEngine.detectRemovedFeatures(args.testCode, session.page); const allIssues = [...staleSelectors, ...elementChanges, ...removedFeatures]; const health = await this.maintenanceEngine.calculateTestHealth({ totalTests: (args.testCode.match(/test\(/g) || []).length, staleSelectors: staleSelectors.length, duplicateTests: 0, flakyTests: 0, coverageGaps: 0 }); const report = `🔍 **Test Health Analysis** **Overall Health Score:** ${health.score || 'N/A'}/100 **Issues Found:** ${allIssues.length} ${allIssues.map((issue) => `• ${issue.type || 'Unknown'}: ${issue.description || issue.message || 'No description'}`).join('\n')} **Recommendations:** ${health.recommendations.map(rec => `• ${rec}`).join('\n')}`; return this.createTextResponse(report); } catch (error) { return this.createErrorResponse(`Failed to analyze test health: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async detectStaleTests(args, session) { try { const staleTests = await this.maintenanceEngine.detectStaleSelectors(args.testCode, session.page); const report = `🔍 **Stale Test Detection** **Found ${staleTests.length} stale test(s):** ${staleTests.map((test) => `• ${test.selector || 'Unknown selector'}: ${test.reason || test.message || 'No reason provided'}`).join('\n')} ${staleTests.length === 0 ? '✅ No stale tests detected!' : '⚠️ Update these tests to prevent failures'}`; return this.createTextResponse(report); } catch (error) { return this.createErrorResponse(`Failed to detect stale tests: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async autoFixTests(args, session) { try { const issues = await this.maintenanceEngine.detectStaleSelectors(args.testCode, session.page); // Get suggestions for fixes const issuesWithFixes = await Promise.all(issues.map(async (issue) => { if (issue.selector) { const suggestions = await this.maintenanceEngine.suggestSelectorUpdate(issue.selector, session.page); if (suggestions.length > 0) { return { ...issue, suggestedFix: suggestions[0].newSelector }; } } return issue; })); const fixedCode = await this.maintenanceEngine.autoFixTests(args.testCode, issuesWithFixes); const appliedFixes = issuesWithFixes.filter(i => i.suggestedFix); const report = `🛠️ **Auto-Fix Test Results** **Applied ${appliedFixes.length} fix(es):** ${appliedFixes.map(fix => `• ${fix.selector}${fix.suggestedFix}`).join('\n')} **Updated Test Code:** \`\`\`javascript ${fixedCode} \`\`\``; return this.createTextResponse(report); } catch (error) { return this.createErrorResponse(`Failed to auto-fix tests: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async findCoverageGaps(args, session) { try { const gaps = await this.maintenanceEngine.findCoverageGaps(args.testSelectors, session.page); // Get element details for gaps const gapDetails = await session.page.evaluate((selectors) => { return selectors.map((selector) => { const el = document.querySelector(selector); if (el) { return { selector, type: el.tagName.toLowerCase(), label: el.innerText?.trim() || el.value || '' }; } return { selector, type: 'unknown', label: '' }; }); }, gaps); const coverage = { percentage: Math.round((args.testSelectors.length / (args.testSelectors.length + gaps.length)) * 100), covered: args.testSelectors.length, total: args.testSelectors.length + gaps.length }; const report = `📊 **Test Coverage Analysis** **Coverage: ${coverage.percentage}%** (${coverage.covered}/${coverage.total} elements) **Uncovered Elements:** ${gapDetails.map((el) => `• ${el.type}: "${el.label}" (${el.selector})`).join('\n')} ${coverage.percentage >= 80 ? '✅ Good coverage!' : '⚠️ Consider adding tests for uncovered elements'}`; return this.createTextResponse(report); } catch (error) { return this.createErrorResponse(`Failed to find coverage gaps: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async generateMaintenanceReport(args, session) { try { const report = await this.maintenanceEngine.generateMaintenanceReport(args.testSuiteId, session.page); const formattedReport = `📋 **Test Maintenance Report** ${typeof report === 'string' ? report : JSON.stringify(report, null, 2)}`; return this.createTextResponse(formattedReport); } catch (error) { return this.createErrorResponse(`Failed to generate maintenance report: ${error instanceof Error ? error.message : 'Unknown error'}`); } } } //# sourceMappingURL=maintenance-handler.js.map