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
154 lines • 7 kB
JavaScript
/**
* Flutter Accessibility Enabler
* Properly enables Flutter's accessibility tree for semantic element detection
*/
export class FlutterAccessibilityEnabler {
/**
* Enable Flutter accessibility through multiple methods
*/
static async enableAccessibility(page) {
// console.log('🔓 Enabling Flutter accessibility...');
// Method 1: Click hidden "Enable accessibility" button if it exists
const accessibilityButtonClicked = await page.evaluate(() => {
// Look for the hidden accessibility button (often at -1, -1)
const buttons = Array.from(document.querySelectorAll('[aria-label*="accessibility" i]'));
const enableButton = buttons.find(b => {
const label = b.getAttribute('aria-label') || '';
const rect = b.getBoundingClientRect();
return label.toLowerCase().includes('enable') &&
label.toLowerCase().includes('accessibility');
});
if (enableButton) {
// Force click even if hidden
enableButton.click();
return true;
}
return false;
});
if (accessibilityButtonClicked) {
// console.log('✅ Clicked "Enable accessibility" button');
await page.waitForTimeout(2000);
return true;
}
// Method 2: Tab navigation to hidden controls
// console.log('⌨️ Trying Tab navigation to enable accessibility...');
// Focus the page
await page.click('body');
// Tab through hidden elements (Flutter often has accessibility toggle as first focusable)
for (let i = 0; i < 5; i++) {
await page.keyboard.press('Tab');
await page.waitForTimeout(100);
// Check if we focused on accessibility control
const focusedElement = await page.evaluate(() => {
const active = document.activeElement;
if (active) {
const label = active.getAttribute('aria-label') || '';
return {
label,
tagName: active.tagName,
isAccessibility: label.toLowerCase().includes('accessibility')
};
}
return null;
});
if (focusedElement?.isAccessibility) {
// console.log('📍 Found accessibility control via Tab navigation');
await page.keyboard.press('Enter');
await page.waitForTimeout(2000);
return true;
}
}
// Method 3: Programmatic enabling via Flutter internals
const programmaticEnabled = await page.evaluate(() => {
// Try to access Flutter's internal configuration
if (window.flutter) {
const flutter = window.flutter;
// Try various ways to enable accessibility
if (flutter.semanticsEnabled !== undefined) {
flutter.semanticsEnabled = true;
}
if (flutter.configuration) {
flutter.configuration.enableAccessibility = true;
}
if (flutter._configuration) {
flutter._configuration.enableAccessibility = true;
}
// Dispatch custom event that Flutter might listen to
window.dispatchEvent(new CustomEvent('flutter-enable-accessibility'));
return true;
}
// Try to find Flutter's initialization script and modify config
const scripts = Array.from(document.querySelectorAll('script'));
const flutterScript = scripts.find(s => s.textContent?.includes('flutterConfiguration') ||
s.textContent?.includes('_flutter.loader'));
if (flutterScript && window._flutter) {
if (window._flutter.loader) {
window._flutter.loader.config = {
...window._flutter.loader.config,
enableAccessibility: true
};
}
return true;
}
return false;
});
if (programmaticEnabled) {
// console.log('🔧 Enabled accessibility programmatically');
await page.waitForTimeout(2000);
return true;
}
// Method 4: Keyboard shortcut (some Flutter apps use this)
// console.log('⌨️ Trying keyboard shortcuts...');
// Try Shift+Tab three times (Flutter pattern)
for (let i = 0; i < 3; i++) {
await page.keyboard.down('Shift');
await page.keyboard.press('Tab');
await page.keyboard.up('Shift');
await page.waitForTimeout(100);
}
// Try Ctrl+Alt+Z (accessibility toggle in some apps)
await page.keyboard.down('Control');
await page.keyboard.down('Alt');
await page.keyboard.press('z');
await page.keyboard.up('Alt');
await page.keyboard.up('Control');
await page.waitForTimeout(2000);
// Check if accessibility was enabled by looking for semantic nodes
const semanticNodesAfter = await page.evaluate(() => {
return document.querySelectorAll('flt-semantics, [role]:not([role="presentation"])').length;
});
// console.log(`📊 Semantic nodes after attempts: ${semanticNodesAfter}`);
return semanticNodesAfter > 20; // Assume success if we have many semantic nodes
}
/**
* Verify accessibility is enabled
*/
static async isAccessibilityEnabled(page) {
return await page.evaluate(() => {
// Check for semantic nodes
const semanticNodes = document.querySelectorAll('flt-semantics, [role]:not([role="presentation"])');
// Check for Flutter accessibility flag
const flutterEnabled = window.flutter?.semanticsEnabled === true;
// Check if we have a reasonable number of semantic nodes
return semanticNodes.length > 20 || flutterEnabled;
});
}
/**
* Wait for accessibility tree to be populated
*/
static async waitForAccessibilityTree(page, timeout = 5000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const nodeCount = await page.evaluate(() => {
return document.querySelectorAll('flt-semantics, [role]:not([role="presentation"])').length;
});
if (nodeCount > 20) {
// console.log(`✅ Accessibility tree populated with ${nodeCount} nodes`);
return;
}
await page.waitForTimeout(500);
}
console.warn('⚠️ Timeout waiting for accessibility tree');
}
}
//# sourceMappingURL=flutter-accessibility-enabler.js.map