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
1,096 lines โข 50.6 kB
JavaScript
/**
* Flutter TDD Integration Handler
* Comprehensive TDD enhancements for Flutter debugging based on Cycle 22 user feedback
* Provides 6 specialized tools for Test-Driven Development workflow acceleration
*/
import { BaseHandler } from './base-handler.js';
import { FlutterTestModeDetector } from '../utils/flutter-test-mode-detector.js';
import { ProviderGapAnalyzer } from '../utils/provider-gap-analyzer.js';
import { TestExpectationTracker } from '../utils/test-expectation-tracker.js';
import { TDDImplementationPlanner } from '../utils/tdd-implementation-planner.js';
export class FlutterTDDIntegrationHandler extends BaseHandler {
testModeDetector;
providerAnalyzer;
expectationTracker;
implementationPlanner;
constructor() {
super();
this.testModeDetector = FlutterTestModeDetector.getInstance();
this.providerAnalyzer = ProviderGapAnalyzer.getInstance();
this.expectationTracker = TestExpectationTracker.getInstance();
this.implementationPlanner = TDDImplementationPlanner.getInstance();
}
tools = [
{
name: 'detect_flutter_test_mode',
description: 'Auto-detect Flutter test environment and provide test-specific debugging configuration. Identifies test framework, mocking setup, and authentication state.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID to analyze for test mode'
},
autoConfigureTestMode: {
type: 'boolean',
description: 'Automatically configure test-optimized debugging settings',
default: true
},
testType: {
type: 'string',
description: 'Expected test type for validation',
enum: ['widget', 'integration', 'unit', 'golden', 'auto'],
default: 'auto'
}
},
required: ['sessionId']
}
},
{
name: 'analyze_provider_gaps',
description: 'Automatically identify missing provider mocks that cause authentication and data issues. Based on Cycle 22 breakthrough - detects unifiedAuthNotifierProvider gaps.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID for provider analysis'
},
testContext: {
type: 'object',
properties: {
testType: { type: 'string', enum: ['widget', 'integration', 'unit'] },
authenticationRequired: { type: 'boolean', default: true },
dataProvidersRequired: {
type: 'array',
items: { type: 'string' },
description: 'List of required data providers'
}
},
required: ['testType']
},
generateMockCode: {
type: 'boolean',
description: 'Generate ready-to-use mock code',
default: true
}
},
required: ['sessionId', 'testContext']
}
},
{
name: 'compare_test_expectations',
description: 'Compare expected widget keys vs actual rendering state. Identifies missing UI components like family_overview_section that cause test failures.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID for expectation comparison'
},
expectedWidgets: {
type: 'array',
items: { type: 'string' },
description: 'List of expected widget keys (e.g., family_overview_section, family_member_status_card_)',
default: ['family_overview_section', 'family_member_status_card_', 'add_family_event_quick_action']
},
generateImplementationPlan: {
type: 'boolean',
description: 'Generate step-by-step implementation plan for missing widgets',
default: true
},
includeCriticalityAnalysis: {
type: 'boolean',
description: 'Analyze which missing widgets are critical vs optional',
default: true
}
},
required: ['sessionId']
}
},
{
name: 'suggest_authentication_mocks',
description: 'Generate comprehensive authentication provider mocks based on discovered gaps. Creates DashboardTestUtils pattern from Cycle 22 success.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID for authentication analysis'
},
authenticationContext: {
type: 'object',
properties: {
requiresUnifiedAuth: { type: 'boolean', default: true },
requiresFamilyData: { type: 'boolean', default: true },
requiresUserSession: { type: 'boolean', default: true },
customProviders: {
type: 'array',
items: { type: 'string' },
description: 'Additional custom providers to mock'
}
}
},
outputFormat: {
type: 'string',
enum: ['dart_code', 'test_utility_class', 'inline_overrides'],
default: 'test_utility_class',
description: 'Format for generated mock code'
}
},
required: ['sessionId']
}
},
{
name: 'track_implementation_progress',
description: 'Monitor test requirement completion in real-time. Shows which widgets are implemented and what still needs work.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID for progress tracking'
},
implementationTarget: {
type: 'object',
properties: {
component: { type: 'string', description: 'Component being implemented (e.g., dashboard, family_overview)' },
requiredWidgets: {
type: 'array',
items: { type: 'string' },
description: 'List of required widget keys'
},
testFile: { type: 'string', description: 'Associated test file path' }
},
required: ['component']
},
trackingMode: {
type: 'string',
enum: ['real_time', 'on_demand', 'milestone'],
default: 'real_time',
description: 'How frequently to update progress'
}
},
required: ['sessionId', 'implementationTarget']
}
},
{
name: 'generate_test_utilities',
description: 'Create reusable test utility code for consistent TDD patterns. Generates DashboardTestUtils and helper functions.',
inputSchema: {
type: 'object',
properties: {
sessionId: {
type: 'string',
description: 'Debug session ID for context analysis'
},
utilityType: {
type: 'string',
enum: ['dashboard_test_utils', 'authentication_mocks', 'widget_finders', 'test_data_builders', 'comprehensive'],
default: 'comprehensive',
description: 'Type of test utility to generate'
},
targetComponents: {
type: 'array',
items: { type: 'string' },
description: 'Components to create utilities for (e.g., dashboard, family_overview, quick_actions)',
default: ['dashboard']
},
includeDebuggingHelpers: {
type: 'boolean',
description: 'Include debugging methods like debugDashboardState()',
default: true
}
},
required: ['sessionId']
}
}
];
async handle(toolName, args, sessions) {
try {
switch (toolName) {
case 'detect_flutter_test_mode':
return this.detectFlutterTestMode(args, sessions);
case 'analyze_provider_gaps':
return this.analyzeProviderGaps(args, sessions);
case 'compare_test_expectations':
return this.compareTestExpectations(args, sessions);
case 'suggest_authentication_mocks':
return this.suggestAuthenticationMocks(args, sessions);
case 'track_implementation_progress':
return this.trackImplementationProgress(args, sessions);
case 'generate_test_utilities':
return this.generateTestUtilities(args, sessions);
default:
throw new Error(`Unknown Flutter TDD tool: ${toolName}`);
}
}
catch (error) {
return this.createErrorResponse(error);
}
}
/**
* Detect Flutter test mode and configure debugging accordingly
*/
async detectFlutterTestMode(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
const testEnvironment = await this.testModeDetector.detectTestEnvironment(args.sessionId, session.page);
// Auto-configure test mode if requested
if (args.autoConfigureTestMode && testEnvironment.isTestMode) {
const testConfig = {
autoMockAuth: true,
skipAnimations: true,
fastPump: true,
providerStateInspection: true,
debugPaintSizeEnabled: testEnvironment.testType === 'widget',
customMocks: testEnvironment.authenticationMocks.gaps
};
this.testModeDetector.configureTestMode(testConfig);
}
const sections = [
'๐งช **Flutter Test Mode Detection Results**',
'',
`**Session ID**: ${args.sessionId}`,
`**Test Mode**: ${testEnvironment.isTestMode ? 'โ
Detected' : 'โ Not detected'}`,
'',
'## ๐ **Test Environment Analysis**',
'',
`**Framework**: ${testEnvironment.testFramework}`,
`**Test Type**: ${testEnvironment.testType}`,
`**Mocking Framework**: ${testEnvironment.mockingFramework || 'None detected'}`,
`**Test Runner Active**: ${testEnvironment.hasTestRunner ? 'Yes' : 'No'}`,
''
];
if (testEnvironment.isTestMode) {
sections.push('## ๐ **Authentication Analysis**');
sections.push(`**Authentication Mocks Detected**: ${testEnvironment.authenticationMocks.detected ? 'Yes' : 'No'}`);
if (testEnvironment.authenticationMocks.providers.length > 0) {
sections.push('**Mocked Providers**:');
testEnvironment.authenticationMocks.providers.forEach(provider => {
sections.push(`- โ
${provider}`);
});
}
if (testEnvironment.authenticationMocks.gaps.length > 0) {
sections.push('**Missing Providers** (Critical for Cycle 22 pattern):');
testEnvironment.authenticationMocks.gaps.forEach(gap => {
sections.push(`- โ ${gap}`);
});
}
sections.push('');
sections.push('## ๐ฏ **Widget Expectations Analysis**');
if (testEnvironment.expectedWidgets.keys.length > 0) {
sections.push('**Expected Widget Keys**:');
testEnvironment.expectedWidgets.keys.forEach(key => {
sections.push(`- ${key}`);
});
}
if (testEnvironment.expectedWidgets.missing.length > 0) {
sections.push('**Missing Widgets** (Implementation targets):');
testEnvironment.expectedWidgets.missing.forEach(missing => {
sections.push(`- โ ${missing}`);
});
}
sections.push('');
sections.push('## โ๏ธ **Test Mode Configuration**');
if (args.autoConfigureTestMode) {
sections.push('**Auto-configured for optimal TDD debugging**:');
sections.push('- โ
Authentication mocking enabled');
sections.push('- โ
Animation skipping enabled');
sections.push('- โ
Fast pump mode enabled');
sections.push('- โ
Provider state inspection enabled');
if (testEnvironment.testType === 'widget') {
sections.push('- โ
Debug paint enabled for widget tests');
}
}
sections.push('');
sections.push('## ๐ก **TDD Workflow Recommendations**');
sections.push('1. **Fix Authentication Gaps**: Use `analyze_provider_gaps` to identify all missing mocks');
sections.push('2. **Compare Expectations**: Use `compare_test_expectations` to see actual vs expected widgets');
sections.push('3. **Generate Test Utils**: Use `generate_test_utilities` to create reusable mock patterns');
sections.push('4. **Track Progress**: Use `track_implementation_progress` to monitor implementation');
}
else {
sections.push('## โ ๏ธ **Not in Test Mode**');
sections.push('**Detected Environment**: Regular Flutter application');
sections.push('**Recommendation**: Use standard Flutter debugging tools or start a test session');
}
return this.createTextResponse(sections.join('\n'));
}
/**
* Analyze provider gaps and generate mock recommendations
*/
async analyzeProviderGaps(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
const context = {
testType: args.testContext.testType,
framework: 'flutter_test', // Default, could be enhanced to detect
authenticationRequired: args.testContext.authenticationRequired,
dataProvidersRequired: args.testContext.dataProvidersRequired || [],
uiRequirements: ['dashboard', 'family_overview'] // Could be parameterized
};
const analysis = await this.providerAnalyzer.analyzeProviderGaps(context, session.page);
const sections = [
'๐ **Provider Gap Analysis**',
'',
`**Session ID**: ${args.sessionId}`,
`**Test Type**: ${context.testType}`,
`**Authentication Required**: ${context.authenticationRequired ? 'Yes' : 'No'}`,
'',
'## ๐ **Analysis Results**',
'',
`**Required Providers**: ${analysis.requiredProviders.length}`,
`**Detected Providers**: ${analysis.detectedProviders.length}`,
`**Missing Providers**: ${analysis.missingProviders.length}`,
`**Conflicting Providers**: ${analysis.conflictingProviders.length}`,
''
];
if (analysis.missingProviders.length > 0) {
sections.push('## โ **Missing Providers (Critical Issues)**');
analysis.missingProviders.forEach(provider => {
const criticalityIcon = provider.criticality === 'critical' ? '๐จ' :
provider.criticality === 'important' ? 'โ ๏ธ' : 'โน๏ธ';
sections.push(`${criticalityIcon} **${provider.name}** (${provider.type})`);
sections.push(` - Criticality: ${provider.criticality}`);
sections.push(` - Dependencies: ${provider.dependencies.join(', ') || 'None'}`);
sections.push('');
});
}
if (analysis.detectedProviders.length > 0) {
sections.push('## โ
**Detected Providers (Working)**');
analysis.detectedProviders.forEach(provider => {
sections.push(`- **${provider.name}** (${provider.type})`);
});
sections.push('');
}
if (analysis.conflictingProviders.length > 0) {
sections.push('## โ ๏ธ **Conflicting Providers**');
analysis.conflictingProviders.forEach(provider => {
sections.push(`- **${provider.name}**: Missing dependencies: ${provider.dependencies.join(', ')}`);
});
sections.push('');
}
if (analysis.recommendations.length > 0) {
sections.push('## ๐ก **Recommendations**');
// Group recommendations by priority
const highPriority = analysis.recommendations.filter(r => r.priority === 'high');
const mediumPriority = analysis.recommendations.filter(r => r.priority === 'medium');
const lowPriority = analysis.recommendations.filter(r => r.priority === 'low');
if (highPriority.length > 0) {
sections.push('### ๐จ **High Priority Actions**');
highPriority.forEach(rec => {
sections.push(`**${rec.action.toUpperCase()}: ${rec.provider}**`);
sections.push(`Reason: ${rec.reason}`);
sections.push(`Related Issues: ${rec.relatedIssues.join(', ')}`);
sections.push('');
});
}
if (mediumPriority.length > 0) {
sections.push('### โ ๏ธ **Medium Priority Actions**');
mediumPriority.forEach(rec => {
sections.push(`**${rec.provider}**: ${rec.reason}`);
});
sections.push('');
}
}
if (args.generateMockCode && analysis.recommendations.length > 0) {
sections.push('## ๐ ๏ธ **Generated Mock Code**');
sections.push('');
analysis.recommendations.forEach(rec => {
if (rec.mockCode) {
sections.push(`### ${rec.provider}`);
sections.push('```dart');
sections.push(rec.mockCode);
sections.push('```');
sections.push('');
}
});
}
sections.push('## ๐ฏ **Next Steps**');
sections.push('1. **Implement missing critical providers** (marked with ๐จ)');
sections.push('2. **Use `suggest_authentication_mocks` to generate comprehensive test utilities**');
sections.push('3. **Run `compare_test_expectations` to validate widget rendering after provider fixes**');
sections.push('4. **Use `track_implementation_progress` to monitor fixes**');
return this.createTextResponse(sections.join('\n'));
}
/**
* Compare test expectations with actual rendering state
*/
async compareTestExpectations(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
// Add expected widgets to tracker if provided
if (args.expectedWidgets) {
args.expectedWidgets.forEach((key) => {
this.expectationTracker.addExpectation({
key,
type: key.endsWith('_') ? 'pattern' : 'exact',
description: `Expected widget: ${key}`,
criticality: 'must_have',
dependencies: []
});
});
}
const trackingResult = await this.expectationTracker.trackExpectations(args.sessionId, session.page);
const sections = [
'๐ฏ **Test Expectations vs Actual Rendering**',
'',
`**Session ID**: ${args.sessionId}`,
`**Overall Status**: ${this.getStatusIcon(trackingResult.overallStatus)} ${trackingResult.overallStatus.toUpperCase()}`,
`**Expectations Met**: ${trackingResult.metExpectations}/${trackingResult.totalExpectations}`,
'',
'## ๐ **Detailed Comparison**',
''
];
trackingResult.comparisons.forEach((comparison, index) => {
const statusIcon = comparison.status === 'met' ? 'โ
' :
comparison.status === 'partially_met' ? 'โ ๏ธ' : 'โ';
sections.push(`### ${index + 1}. ${statusIcon} ${comparison.expectation.key}`);
sections.push(`**Status**: ${comparison.status}`);
sections.push(`**Description**: ${comparison.expectation.description}`);
sections.push(`**Gap**: ${comparison.gap}`);
if (comparison.actualElements.length > 0) {
sections.push(`**Found Elements**: ${comparison.actualElements.join(', ')}`);
}
sections.push(`**Recommendation**: ${comparison.recommendation}`);
sections.push(`**Implementation Hint**: ${comparison.implementationHint}`);
sections.push('');
});
if (trackingResult.criticalGaps.length > 0) {
sections.push('## ๐จ **Critical Gaps (Blocking Tests)**');
trackingResult.criticalGaps.forEach(gap => {
sections.push(`- ${gap}`);
});
sections.push('');
}
if (args.generateImplementationPlan && trackingResult.implementationPlan.length > 0) {
sections.push('## ๐ **Implementation Plan**');
sections.push('');
trackingResult.implementationPlan.forEach(step => {
const effortIcon = step.estimatedEffort === 'small' ? '๐ข' :
step.estimatedEffort === 'medium' ? '๐ก' : '๐ด';
sections.push(`### ${step.order}. ${step.action}`);
sections.push(`**Target**: ${step.target}`);
sections.push(`**Effort**: ${effortIcon} ${step.estimatedEffort}`);
sections.push(`**Reason**: ${step.reason}`);
if (step.dependencies.length > 0) {
sections.push(`**Dependencies**: ${step.dependencies.join(', ')}`);
}
if (step.code) {
sections.push('**Code Template**:');
sections.push('```dart');
sections.push(step.code);
sections.push('```');
}
sections.push('');
});
}
if (args.includeCriticalityAnalysis) {
sections.push('## ๐ญ **Criticality Analysis**');
const critical = trackingResult.comparisons.filter(c => c.expectation.criticality === 'must_have');
const important = trackingResult.comparisons.filter(c => c.expectation.criticality === 'should_have');
const optional = trackingResult.comparisons.filter(c => c.expectation.criticality === 'nice_to_have');
sections.push(`**Must Have**: ${critical.filter(c => c.status === 'met').length}/${critical.length} โ
`);
sections.push(`**Should Have**: ${important.filter(c => c.status === 'met').length}/${important.length} โ ๏ธ`);
sections.push(`**Nice to Have**: ${optional.filter(c => c.status === 'met').length}/${optional.length} โน๏ธ`);
sections.push('');
}
sections.push('## ๐ฏ **Next Steps**');
sections.push('1. **Implement critical missing widgets** first (marked with โ)');
sections.push('2. **Use implementation plan** as step-by-step guide');
sections.push('3. **Use `track_implementation_progress`** to monitor each implementation');
sections.push('4. **Re-run this tool** after implementations to validate progress');
return this.createTextResponse(sections.join('\n'));
}
/**
* Generate authentication mock suggestions
*/
async suggestAuthenticationMocks(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
// Analyze current provider state first
const context = {
testType: 'widget', // Default for auth mocking
framework: 'flutter_test',
authenticationRequired: true,
dataProvidersRequired: args.authenticationContext?.customProviders || [],
uiRequirements: ['dashboard', 'authentication']
};
const analysis = await this.providerAnalyzer.analyzeProviderGaps(context, session.page);
const sections = [
'๐ **Authentication Mock Suggestions**',
'',
`**Session ID**: ${args.sessionId}`,
`**Output Format**: ${args.outputFormat}`,
'',
'## ๐ฏ **Authentication Context Analysis**',
''
];
const authContext = args.authenticationContext || {};
sections.push(`**Unified Auth Required**: ${authContext.requiresUnifiedAuth !== false ? 'Yes' : 'No'}`);
sections.push(`**Family Data Required**: ${authContext.requiresFamilyData !== false ? 'Yes' : 'No'}`);
sections.push(`**User Session Required**: ${authContext.requiresUserSession !== false ? 'Yes' : 'No'}`);
if (authContext.customProviders?.length > 0) {
sections.push(`**Custom Providers**: ${authContext.customProviders.join(', ')}`);
}
sections.push('');
// Generate mock code based on format
sections.push('## ๐ ๏ธ **Generated Mock Code**');
sections.push('');
switch (args.outputFormat) {
case 'test_utility_class':
sections.push(this.generateTestUtilityClass(analysis, authContext));
break;
case 'inline_overrides':
sections.push(this.generateInlineOverrides(analysis, authContext));
break;
case 'dart_code':
default:
sections.push(this.generateDartMockCode(analysis, authContext));
break;
}
sections.push('## ๐ **Usage Instructions**');
sections.push('');
switch (args.outputFormat) {
case 'test_utility_class':
sections.push('1. **Create** a new file `test/utils/dashboard_test_utils.dart`');
sections.push('2. **Copy** the generated class code above');
sections.push('3. **Import** in your test files: `import "utils/dashboard_test_utils.dart"`');
sections.push('4. **Use** in tests: `overrides: DashboardTestUtils.getAuthenticatedOverrides()`');
break;
case 'inline_overrides':
sections.push('1. **Copy** the override list into your test');
sections.push('2. **Use** in ProviderScope: `overrides: [/* paste here */]`');
sections.push('3. **Customize** mock data as needed for specific tests');
break;
default:
sections.push('1. **Integrate** the mock providers into your test setup');
sections.push('2. **Customize** the mock responses based on test scenarios');
sections.push('3. **Ensure** all dependencies are properly mocked');
}
sections.push('');
sections.push('## ๐งช **Testing Pattern (Cycle 22 Success)**');
sections.push('```dart');
sections.push(`testWidgets('dashboard shows authenticated content', (WidgetTester tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: DashboardTestUtils.getAuthenticatedOverrides(),
child: const MyApp(),
),
);
// Now tests should pass - dashboard shows authenticated content instead of login
expect(find.byKey(const Key('family_overview_section')), findsOneWidget);
expect(find.text('Login'), findsNothing); // Should not show login screen
});`);
sections.push('```');
sections.push('');
sections.push('## ๐ก **Pro Tips**');
sections.push('- **Always mock `unifiedAuthNotifierProvider`** - this was the critical gap from Cycle 22');
sections.push('- **Use consistent test data** across all mocks for predictable results');
sections.push('- **Add debugging helpers** like `debugDashboardState()` to troubleshoot failing tests');
sections.push('- **Mock at the right level** - provider level, not UI level');
sections.push('');
sections.push('## ๐ฏ **Next Steps**');
sections.push('1. **Implement** the generated mock code in your test setup');
sections.push('2. **Run** your failing tests to see authentication issues resolved');
sections.push('3. **Use `compare_test_expectations`** to validate widget rendering');
sections.push('4. **Use `track_implementation_progress`** to monitor test progress');
return this.createTextResponse(sections.join('\n'));
}
/**
* Track implementation progress against test requirements
*/
async trackImplementationProgress(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
const target = args.implementationTarget;
const trackingResult = await this.expectationTracker.trackExpectations(args.sessionId, session.page);
const sections = [
'๐ **Implementation Progress Tracking**',
'',
`**Session ID**: ${args.sessionId}`,
`**Component**: ${target.component}`,
`**Tracking Mode**: ${args.trackingMode}`,
`**Timestamp**: ${new Date().toISOString()}`,
'',
'## ๐ฏ **Progress Overview**',
''
];
const progress = Math.round((trackingResult.metExpectations / trackingResult.totalExpectations) * 100);
const progressBar = this.generateProgressBar(progress);
sections.push(`**Overall Progress**: ${progressBar} ${progress}%`);
sections.push(`**Completed**: ${trackingResult.metExpectations}/${trackingResult.totalExpectations} requirements`);
sections.push(`**Status**: ${this.getStatusIcon(trackingResult.overallStatus)} ${trackingResult.overallStatus}`);
sections.push('');
if (target.requiredWidgets) {
sections.push('## ๐ **Widget Implementation Status**');
sections.push('');
target.requiredWidgets.forEach((widgetKey) => {
const comparison = trackingResult.comparisons.find(c => c.expectation.key === widgetKey);
if (comparison) {
const statusIcon = comparison.status === 'met' ? 'โ
' :
comparison.status === 'partially_met' ? 'โ ๏ธ' : 'โ';
sections.push(`${statusIcon} **${widgetKey}**`);
sections.push(` Status: ${comparison.status}`);
sections.push(` Gap: ${comparison.gap}`);
if (comparison.status !== 'met') {
sections.push(` Next: ${comparison.recommendation}`);
}
}
else {
sections.push(`โ **${widgetKey}** - Not tracked (add to expectations)`);
}
sections.push('');
});
}
if (trackingResult.criticalGaps.length > 0) {
sections.push('## ๐จ **Blocking Issues**');
trackingResult.criticalGaps.forEach(gap => {
sections.push(`- ${gap}`);
});
sections.push('');
}
// Implementation plan for remaining work
const remainingWork = trackingResult.implementationPlan.filter(step => !trackingResult.comparisons.some(c => c.expectation.key === step.target && c.status === 'met'));
if (remainingWork.length > 0) {
sections.push('## ๐ **Remaining Work**');
sections.push('');
remainingWork.forEach(step => {
const priority = step.estimatedEffort === 'small' ? '๐ข Quick' :
step.estimatedEffort === 'medium' ? '๐ก Medium' : '๐ด Complex';
sections.push(`${step.order}. **${step.action}** (${priority})`);
sections.push(` Target: ${step.target}`);
sections.push(` Reason: ${step.reason}`);
sections.push('');
});
}
if (args.trackingMode === 'real_time') {
sections.push('## โฑ๏ธ **Real-time Monitoring Active**');
sections.push('- Progress will update automatically as widgets are implemented');
sections.push('- Use browser refresh or `take_screenshot` to trigger updates');
sections.push('- Critical gaps will be highlighted immediately');
sections.push('');
}
if (target.testFile) {
sections.push('## ๐งช **Associated Test File**');
sections.push(`**File**: ${target.testFile}`);
sections.push('**Recommendation**: Run tests after each implementation to validate progress');
sections.push('');
}
sections.push('## ๐ฏ **Next Actions**');
if (progress === 100) {
sections.push('๐ **Implementation Complete!**');
sections.push('1. **Run all tests** to ensure everything passes');
sections.push('2. **Take final screenshot** to document completed state');
sections.push('3. **Consider refactoring** for code quality improvements');
}
else if (progress >= 75) {
sections.push('๐ **Nearly Complete!**');
sections.push('1. **Focus on remaining critical gaps**');
sections.push('2. **Validate each implementation immediately**');
sections.push('3. **Prepare for final testing phase**');
}
else if (progress >= 50) {
sections.push('โก **Good Progress!**');
sections.push('1. **Continue with implementation plan**');
sections.push('2. **Address any blocking issues first**');
sections.push('3. **Validate implementations as you go**');
}
else {
sections.push('๐ง **Getting Started**');
sections.push('1. **Fix any authentication/provider issues first**');
sections.push('2. **Implement critical widgets before optional ones**');
sections.push('3. **Use generated implementation plan as guide**');
}
return this.createTextResponse(sections.join('\n'));
}
/**
* Generate reusable test utilities
*/
async generateTestUtilities(args, sessions) {
const session = this.getSessionWithTracking(args.sessionId, sessions);
const sections = [
'๐ ๏ธ **Test Utility Code Generator**',
'',
`**Session ID**: ${args.sessionId}`,
`**Utility Type**: ${args.utilityType}`,
`**Target Components**: ${args.targetComponents.join(', ')}`,
`**Include Debugging Helpers**: ${args.includeDebuggingHelpers ? 'Yes' : 'No'}`,
'',
'## ๐ฆ **Generated Test Utilities**',
''
];
switch (args.utilityType) {
case 'comprehensive':
sections.push(this.generateComprehensiveTestUtils(args.targetComponents, args.includeDebuggingHelpers));
break;
case 'dashboard_test_utils':
sections.push(this.generateDashboardTestUtils(args.includeDebuggingHelpers));
break;
case 'authentication_mocks':
sections.push(this.generateAuthenticationMockUtils());
break;
case 'widget_finders':
sections.push(this.generateWidgetFinderUtils(args.targetComponents));
break;
case 'test_data_builders':
sections.push(this.generateTestDataBuilders(args.targetComponents));
break;
default:
sections.push(this.generateComprehensiveTestUtils(args.targetComponents, args.includeDebuggingHelpers));
}
sections.push('## ๐ **Usage Instructions**');
sections.push('');
sections.push('1. **Create file**: `test/utils/test_utilities.dart`');
sections.push('2. **Copy** the generated code above');
sections.push('3. **Import** in test files: `import "../utils/test_utilities.dart"`');
sections.push('4. **Use** the utility methods in your tests');
sections.push('');
sections.push('## ๐งช **Example Test Usage**');
sections.push('```dart');
sections.push(`testWidgets('dashboard displays correctly', (WidgetTester tester) async {
// Use the generated utilities
await TestUtilities.pumpAuthenticatedDashboard(tester);
// Debug current state if needed
TestUtilities.debugDashboardState(tester);
// Validate expected widgets
TestUtilities.expectDashboardWidgets(tester);
// Take screenshot for documentation
// Use ai-debug take_screenshot tool
});`);
sections.push('```');
sections.push('');
sections.push('## ๐ก **Best Practices**');
sections.push('- **Reuse utilities** across multiple test files for consistency');
sections.push('- **Customize mock data** for specific test scenarios');
sections.push('- **Use debugging helpers** when tests fail to understand state');
sections.push('- **Keep utilities focused** - separate concerns into different utility classes');
sections.push('');
sections.push('## ๐ฏ **Next Steps**');
sections.push('1. **Implement** the generated utility code');
sections.push('2. **Update existing tests** to use the utilities');
sections.push('3. **Run tests** to validate utilities work correctly');
sections.push('4. **Use `track_implementation_progress`** to monitor test improvements');
return this.createTextResponse(sections.join('\n'));
}
// Helper methods for generating different types of code
generateTestUtilityClass(analysis, authContext) {
const missingProviders = analysis.missingProviders;
const mocks = missingProviders.map(provider => ` ${provider.mockPattern}`).join(',\n');
return `### DashboardTestUtils Class
\`\`\`dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
class DashboardTestUtils {
/// Comprehensive authentication overrides based on Cycle 22 success pattern
static List<Override> getAuthenticatedOverrides() => [
${mocks}
];
/// Debug current dashboard state - shows which widgets are present
static void debugDashboardState(WidgetTester tester) {
final expectedKeys = [
'family_overview_section',
'family_member_status_card_1',
'family_member_status_card_2',
'add_family_event_quick_action',
'add_family_chore_quick_action',
'family_wellbeing_indicator',
'family_calendar_sync_status'
];
print('=== Dashboard State Debug ===');
for (final key in expectedKeys) {
final finder = find.byKey(Key(key));
final elementCount = finder.evaluate().length;
print('Widget \\$key: \\$\{elementCount > 0 ? "โ
Found (\\$\{elementCount\})" : "โ Missing"\}');
}
print('=============================');
}
/// Pump authenticated dashboard with all required providers
static Future<void> pumpAuthenticatedDashboard(WidgetTester tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: getAuthenticatedOverrides(),
child: const MaterialApp(
home: DashboardPage(),
),
),
);
await tester.pumpAndSettle();
}
/// Validate all expected dashboard widgets are present
static void expectDashboardWidgets(WidgetTester tester) {
expect(find.byKey(const Key('family_overview_section')), findsOneWidget);
expect(find.byKey(const Key('add_family_event_quick_action')), findsOneWidget);
expect(find.byKey(const Key('add_family_chore_quick_action')), findsOneWidget);
}
}
\`\`\``;
}
generateInlineOverrides(analysis, authContext) {
const mocks = analysis.missingProviders.map(provider => ` ${provider.mockPattern}`).join(',\n');
return `### Inline Provider Overrides
\`\`\`dart
// Use this in your ProviderScope:
overrides: [
${mocks}
]
\`\`\``;
}
generateDartMockCode(analysis, authContext) {
let code = '### Individual Mock Providers\n\n```dart\n';
analysis.missingProviders.forEach(provider => {
code += `// ${provider.name} (${provider.type} - ${provider.criticality})\n`;
code += `${provider.mockPattern}\n\n`;
});
code += '```';
return code;
}
generateComprehensiveTestUtils(components, includeDebugging) {
return `### Comprehensive Test Utilities
\`\`\`dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
class TestUtilities {
/// Authentication overrides for all test scenarios
static List<Override> getAuthenticatedOverrides() => [
unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(authenticated: true)),
currentUserProvider.overrideWith((ref) => TestUser.default()),
unifiedFamilyMembersProvider.overrideWith((ref) => MockFamilyMembers.default()),
primaryHouseholdNameProvider.overrideWith((ref) => "Test Household"),
];
/// Data providers with realistic test data
static List<Override> getDataOverrides() => [
unifiedFamilyMembersProvider.overrideWith((ref) => [
TestMember(id: '1', name: 'Alice', status: 'active'),
TestMember(id: '2', name: 'Bob', status: 'busy'),
]),
];
/// Configuration overrides for consistent testing
static List<Override> getConfigOverrides() => [
dashboardLayoutConfigProvider.overrideWith((ref) => DashboardConfig.test()),
];
/// All overrides combined
static List<Override> getAllOverrides() => [
...getAuthenticatedOverrides(),
...getDataOverrides(),
...getConfigOverrides(),
];
/// Pump widget with authentication
static Future<void> pumpAuthenticatedWidget(
WidgetTester tester,
Widget widget, {
List<Override>? additionalOverrides,
}) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
...getAllOverrides(),
...?additionalOverrides,
],
child: MaterialApp(home: widget),
),
);
await tester.pumpAndSettle();
}
${includeDebugging ? this.getDebuggingHelperMethods() : ''}
/// Common widget finders
static class Finders {
static Finder familyOverviewSection = find.byKey(const Key('family_overview_section'));
static Finder addEventButton = find.byKey(const Key('add_family_event_quick_action'));
static Finder addChoreButton = find.byKey(const Key('add_family_chore_quick_action'));
static Finder familyMemberCard(String memberId) =>
find.byKey(Key('family_member_status_card_\$memberId'));
}
/// Common expectations
static void expectDashboardLoaded(WidgetTester tester) {
expect(Finders.familyOverviewSection, findsOneWidget);
expect(find.text('Login'), findsNothing); // Should not show login
}
static void expectFamilyMembersDisplayed(WidgetTester tester, List<String> memberIds) {
for (final id in memberIds) {
expect(Finders.familyMemberCard(id), findsOneWidget);
}
}
}
\`\`\``;
}
getDebuggingHelperMethods() {
return `
/// Debug current widget state
static void debugWidgetState(WidgetTester tester) {
final expectedKeys = [
'family_overview_section',
'family_member_status_card_1',
'family_member_status_card_2',
'add_family_event_quick_action',
'add_family_chore_quick_action',
'family_wellbeing_indicator',
];
print('=== Widget State Debug ===');
for (final key in expectedKeys) {
final finder = find.byKey(Key(key));
final elementCount = finder.evaluate().length;
print('Widget \\$key: \\$\{elementCount > 0 ? "โ
Found (\\$\{elementCount\})" : "โ Missing"\}');
}
// Check for authentication state
final loginFinderElements = find.text('Login');
print('Login screen: \\$\{loginFinderElements.evaluate().length > 0 ? "โ Visible (auth issue)" : "โ
Hidden"\}');
print('=========================');
}
/// Debug provider state
static void debugProviderState(WidgetTester tester) {
// This would need to be customized based on your provider structure
print('=== Provider State Debug ===');
print('Use this method to inspect provider values during test failures');
print('============================');
}`;
}
generateDashboardTestUtils(includeDebugging) {
return `### Dashboard-Specific Test Utils
\`\`\`dart
class DashboardTestUtils {
static List<Override> getAuthenticatedOverrides() => [
unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(authenticated: true)),
currentUserProvider.overrideWith((ref) => TestUser.default()),
unifiedFamilyMembersProvider.overrideWith((ref) => MockFamilyMembers.default()),
primaryHouseholdNameProvider.overrideWith((ref) => "Test Household"),
];
${includeDebugging ? this.getDebuggingHelperMethods() : ''}
}
\`\`\``;
}
generateAuthenticationMockUtils() {
return `### Authentication Mock Utilities
\`\`\`dart
class AuthMockUtils {
static List<Override> authenticatedUser() => [
unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(authenticated: true)),
currentUserProvider.overrideWith((ref) => TestUser.authenticated()),
];
static List<Override> unauthenticatedUser() => [
unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(authenticated: false)),
currentUserProvider.overrideWith((ref) => null),
];
static List<Override> adminUser() => [
unifiedAuthNotifierProvider.overrideWith((ref) => MockAuthNotifier(
authenticated: true,
permissions: ['admin']
)),
currentUserProvider.overrideWith((ref) => TestUser.admin()),
];
}
\`\`\``;
}
generateWidgetFinderUtils(components) {
return `### Widget Finder Utilities
\`\`\`dart
class WidgetFinders {
// Dashboard widgets
static Finder familyOverviewSection = find.byKey(const Key('family_overview_section'));
static Finder addEventButton = find.byKey(const Key('add_family_event_quick_action'));
static Finder addChoreButton = find.byKey(const Key('add_family_chore_quick_action'));
// Dynamic finders
static Finder familyMemberCard(String memberId) =>
find.byKey(Key('family_member_status_card_\$memberId'));
static Finder anyFamilyMemberCard() =>
find.byWidgetPredicate((widget) =>
widget.key?.toString().contains('family_member_status_card_') ?? false);
// Validation helpers
static void expectAllDashboardWidgets() {
expect(familyOverviewSection, findsOneWidget);
expect(addEventButton, findsOneWidget);
expect(addChoreButton, findsOneWidget);
}
}
\`\`\``;
}
generateTestDataBuilders(components) {
return `### Test Data Builders
\`\`\`dart
class TestDataBuilders {
static TestUser createUser({
String id = 'test-user-1',
String name = 'Test User',
bool isAdmin = false,
}) {
return TestUser(
id: id,
name: name,
permissions: isAdmin ? ['admin'] : ['user'],
);
}
static List<TestMember> createFamilyMembers({
int count = 2,
}) {
return List.generate(count, (index) => TestMember(
id: 'member-\${index + 1}',
name: 'Member \${index + 1}',
status: index % 2 == 0 ? 'active' : 'busy',
));
}
static DashboardConfig createDashboardConfig({
bool showWellbeing = true,
bool showCalendarSync = true,
}) {
return DashboardConfig(
showWellbeingIndicator: showWellbeing,
showCalendarSyncStatus: showCalendarSync,
);
}
}
\`\`\``;
}
// Helper methods for formatting
getStatusIcon(status) {
switch (status) {
case 'passing': return 'โ
';
case 'partial': return 'โ ๏ธ';
case 'failing': return 'โ';
case 'met': return 'โ
';
case 'partially_met': return 'โ ๏ธ';
case 'not_met': return 'โ';
default: return 'โ';
}
}
generateProgressBar(percentage) {
const filled = Math.floor(percentage / 10);
const empty = 10 - filled;
return 'โ'.repeat(filled) + 'โ'.repeat(empty);
}
}
//# sourceMappingURL=flutter-tdd-integration-handler.js.map