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
JavaScript
/**
* 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