// probe3:开启 Flutter web semantics(Enable accessibility),看能否得到 DOM 输入框 const { chromium } = require('playwright'); const BASE = 'http://127.0.0.1:8099'; (async () => { const browser = await chromium.launch({ headless: true }); const page = await (await browser.newContext({ viewport: { width: 1280, height: 900 } })).newPage(); await page.goto(BASE + '/login', { waitUntil: 'load', timeout: 60000 }); await page.waitForTimeout(5000); // 方法1:点击 flt-semantics-placeholder("Enable accessibility") const ph = await page.locator('flt-semantics-placeholder').count(); console.log('placeholder 数:', ph); if (ph > 0) { await page.locator('flt-semantics-placeholder').click({ force: true }).catch(e => console.log('点击 placeholder 失败:', e.message.slice(0,60))); await page.waitForTimeout(3000); } // 方法2:尝试 JS 开启(多种已知方式) await page.evaluate(() => { // 部分版本支持 if (window._flutter) { try { window._flutter.semanticsEnabled = true; } catch(e){} } }); const textbox = await page.locator('[role="textbox"]').count(); const btn = await page.locator('[role="button"]').count(); const input = await page.locator('input').count(); console.log(`开启后: role=textbox=${textbox}, role=button=${btn}, input=${input}`); // 列出 semantics 元素的 label(找用户名/密码/登录按钮) const labels = await page.evaluate(() => { return [...document.querySelectorAll('[role="textbox"], [role="button"], [aria-label]')] .map(e => ({ role: e.getAttribute('role'), label: e.getAttribute('aria-label'), name: e.tagName })) .filter(x => x.label && x.label.length < 40) .slice(0, 25); }); console.log('semantics labels:', JSON.stringify(labels)); await page.screenshot({ path: 'login_semantics.png' }); await browser.close(); })().catch(e => { console.error('失败:', e.message); process.exit(1); });