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

351 lines (349 loc) • 14.2 kB
/** * Provider Gap Analyzer * Identifies missing provider mocks in Flutter tests * Based on Cycle 22 user feedback - authentication issues detection */ export class ProviderGapAnalyzer { static instance; static getInstance() { if (!ProviderGapAnalyzer.instance) { ProviderGapAnalyzer.instance = new ProviderGapAnalyzer(); } return ProviderGapAnalyzer.instance; } providerRegistry = new Map(); constructor() { this.initializeProviderRegistry(); } /** * Initialize the registry of known providers from Cycle 22 experience */ initializeProviderRegistry() { const knownProviders = [ // Authentication Providers (Critical from Cycle 22) { name: 'unifiedAuthNotifierProvider', type: 'auth', criticality: 'critical', mockPattern: 'unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(authenticated: true))', dependencies: [], testUtility: 'DashboardTestUtils.getAuthenticatedOverrides()' }, { name: 'currentUserProvider', type: 'auth', criticality: 'important', mockPattern: 'currentUserProvider.overrideWith((ref) => TestUser.default())', dependencies: ['unifiedAuthNotifierProvider'], testUtility: 'DashboardTestUtils.getAuthenticatedOverrides()' }, // Data Providers { name: 'unifiedFamilyMembersProvider', type: 'data', criticality: 'critical', mockPattern: 'unifiedFamilyMembersProvider.overrideWith((ref) => MockFamilyMembers.default())', dependencies: ['unifiedAuthNotifierProvider'], testUtility: 'DashboardTestUtils.getAuthenticatedOverrides()' }, { name: 'primaryHouseholdNameProvider', type: 'data', criticality: 'important', mockPattern: 'primaryHouseholdNameProvider.overrideWith((ref) => "Test Household")', dependencies: ['unifiedAuthNotifierProvider'], testUtility: 'DashboardTestUtils.getAuthenticatedOverrides()' }, // Configuration Providers { name: 'dashboardLayoutConfigProvider', type: 'config', criticality: 'optional', mockPattern: 'dashboardLayoutConfigProvider.overrideWith((ref) => MockDashboardConfig.default())', dependencies: [], testUtility: 'DashboardTestUtils.getConfigOverrides()' }, // State Providers { name: 'authStateProvider', type: 'state', criticality: 'important', mockPattern: 'authStateProvider.overrideWith((ref) => AuthState.authenticated())', dependencies: ['unifiedAuthNotifierProvider'], testUtility: 'DashboardTestUtils.getStateOverrides()' }, { name: 'userSessionProvider', type: 'state', criticality: 'important', mockPattern: 'userSessionProvider.overrideWith((ref) => MockUserSession.active())', dependencies: ['currentUserProvider'], testUtility: 'DashboardTestUtils.getSessionOverrides()' } ]; knownProviders.forEach(provider => { this.providerRegistry.set(provider.name, provider); }); } /** * Analyze provider gaps in the current test environment */ async analyzeProviderGaps(context, page) { const analysis = { requiredProviders: [], detectedProviders: [], missingProviders: [], conflictingProviders: [], recommendations: [] }; // Determine required providers based on context analysis.requiredProviders = this.getRequiredProviders(context); // Detect what's currently available if (page) { analysis.detectedProviders = await this.detectCurrentProviders(page); } // Find gaps analysis.missingProviders = this.findMissingProviders(analysis.requiredProviders, analysis.detectedProviders); // Find conflicts analysis.conflictingProviders = this.findConflictingProviders(analysis.detectedProviders); // Generate recommendations analysis.recommendations = this.generateRecommendations(analysis.missingProviders, analysis.conflictingProviders, context); return analysis; } /** * Get required providers based on test context */ getRequiredProviders(context) { const required = []; // Authentication always required for dashboard tests if (context.authenticationRequired) { required.push(this.providerRegistry.get('unifiedAuthNotifierProvider'), this.providerRegistry.get('currentUserProvider')); } // Data providers for dashboard functionality if (context.testType === 'widget' || context.testType === 'integration') { required.push(this.providerRegistry.get('unifiedFamilyMembersProvider'), this.providerRegistry.get('primaryHouseholdNameProvider')); } // UI state providers if (context.uiRequirements.includes('dashboard') || context.uiRequirements.includes('family_overview')) { required.push(this.providerRegistry.get('authStateProvider'), this.providerRegistry.get('userSessionProvider')); } // Configuration providers for complex UI if (context.framework === 'integration_test') { required.push(this.providerRegistry.get('dashboardLayoutConfigProvider')); } return required.filter(provider => provider !== undefined); } /** * Detect currently available providers in the test environment */ async detectCurrentProviders(page) { const detected = []; try { const providerStatus = await page.evaluate(() => { const mocks = {}; // Check for Flutter provider overrides if (typeof window.flutter?.mocks !== 'undefined') { Object.assign(mocks, window.flutter.mocks); } // Check for Riverpod provider overrides if (typeof window.providerContainer !== 'undefined') { const container = window.providerContainer; // Get list of overridden providers if (container.overrides) { mocks.riverpodOverrides = container.overrides.map((override) => override.provider?.name || 'unknown'); } } return mocks; }); // Match detected providers with our registry for (const [providerName, providerInfo] of this.providerRegistry) { if (providerStatus[providerName] || (providerStatus.riverpodOverrides && providerStatus.riverpodOverrides.includes(providerName))) { detected.push(providerInfo); } } } catch (error) { console.warn('Error detecting current providers:', error); } return detected; } /** * Find missing providers */ findMissingProviders(required, detected) { const detectedNames = new Set(detected.map(p => p.name)); return required.filter(provider => !detectedNames.has(provider.name)); } /** * Find conflicting providers */ findConflictingProviders(detected) { const conflicts = []; // Check for dependency conflicts detected.forEach(provider => { provider.dependencies.forEach(depName => { const dependency = this.providerRegistry.get(depName); if (dependency && !detected.some(d => d.name === depName)) { // Dependency is missing but provider is present conflicts.push(provider); } }); }); return [...new Set(conflicts)]; // Remove duplicates } /** * Generate recommendations based on analysis */ generateRecommendations(missing, conflicting, context) { const recommendations = []; // Add missing critical providers missing .filter(provider => provider.criticality === 'critical') .forEach(provider => { recommendations.push({ action: 'add', provider: provider.name, reason: `Critical provider missing - required for ${context.testType} test authentication`, mockCode: this.generateMockCode(provider, context), priority: 'high', relatedIssues: ['Authentication failure', 'Widget not found', 'Empty state rendering'] }); }); // Add missing important providers missing .filter(provider => provider.criticality === 'important') .forEach(provider => { recommendations.push({ action: 'add', provider: provider.name, reason: `Important provider missing - affects ${provider.type} functionality`, mockCode: this.generateMockCode(provider, context), priority: 'medium', relatedIssues: this.getRelatedIssues(provider) }); }); // Fix conflicting providers conflicting.forEach(provider => { recommendations.push({ action: 'fix', provider: provider.name, reason: `Provider has missing dependencies: ${provider.dependencies.join(', ')}`, mockCode: this.generateDependencyFixCode(provider), priority: 'high', relatedIssues: ['Provider dependency error', 'Runtime exception'] }); }); // Generate comprehensive test utility recommendation if (missing.length > 2 || conflicting.length > 0) { recommendations.push({ action: 'enhance', provider: 'DashboardTestUtils', reason: 'Multiple provider issues detected - create comprehensive test utility', mockCode: this.generateTestUtilityCode(missing, context), priority: 'high', relatedIssues: ['Test maintenance overhead', 'Inconsistent mocking patterns'] }); } return recommendations; } /** * Generate mock code for a provider */ generateMockCode(provider, context) { if (provider.testUtility) { return `// Use test utility:\n${provider.testUtility}`; } let mockCode = provider.mockPattern; // Customize based on context if (context.testType === 'integration') { mockCode = mockCode.replace('Mock', 'Integration'); } if (context.authenticationRequired && provider.type === 'auth') { mockCode = mockCode.replace('authenticated: true', 'authenticated: true, permissions: ["admin"]'); } return mockCode; } /** * Generate dependency fix code */ generateDependencyFixCode(provider) { const dependencies = provider.dependencies .map(depName => { const dep = this.providerRegistry.get(depName); return dep ? dep.mockPattern : `// TODO: Add ${depName} mock`; }) .join(',\n '); return `// Fix dependencies first:\n[\n ${dependencies},\n ${provider.mockPattern}\n]`; } /** * Generate comprehensive test utility code */ generateTestUtilityCode(missing, context) { const mocks = missing.map(provider => ` ${provider.mockPattern}`).join(',\n'); return `// Create comprehensive test utility: class DashboardTestUtils { static List<Override> getAuthenticatedOverrides() => [ ${mocks} ]; static void debugDashboardState(WidgetTester tester) { final keys = ['family_overview_section', 'family_member_status_card_*']; for (final key in keys) { print('Widget \$key: \${find.byKey(Key(key)).evaluate().length}'); } } static Future<void> pumpAuthenticatedDashboard(WidgetTester tester) async { await tester.pumpWidget( ProviderScope( overrides: getAuthenticatedOverrides(), child: MyApp(), ), ); await tester.pumpAndSettle(); } }`; } /** * Get related issues for a provider type */ getRelatedIssues(provider) { const issueMap = { 'auth': ['Login screen shown instead of dashboard', 'Authentication state errors'], 'data': ['Empty lists', 'Null data exceptions', 'Widget not found'], 'state': ['Inconsistent UI state', 'State management errors'], 'config': ['Layout issues', 'Configuration defaults used'], 'ui': ['UI component failures', 'Theme issues'], 'unknown': ['General provider issues'] }; return issueMap[provider.type] || issueMap['unknown']; } /** * Add custom provider to registry */ addProvider(provider) { this.providerRegistry.set(provider.name, provider); } /** * Get provider info by name */ getProvider(name) { return this.providerRegistry.get(name); } /** * Get all providers by type */ getProvidersByType(type) { return Array.from(this.providerRegistry.values()) .filter(provider => provider.type === type); } /** * Clear provider registry (for testing) */ clearRegistry() { this.providerRegistry.clear(); this.initializeProviderRegistry(); } } //# sourceMappingURL=provider-gap-analyzer.js.map