- download: desktop_download_apps SingleChildScrollView 加 primary:true (Scrollbar 缺 ScrollPosition) - contact-stores: checkDomainAvailability async 后 setState 加 mounted 保护 (dispose 后 setState) - buy-service: _loadData 加 data 结构校验 + mounted 保护 (API 400 无效参数时 data 为错误结构 -> RangeError)
69 lines
2.9 KiB
JavaScript
69 lines
2.9 KiB
JavaScript
// 探测脚本:检查 Flutter renderer + 登录页 DOM + Hive 存储后端
|
||
const { chromium } = require('playwright');
|
||
|
||
const BASE = 'http://127.0.0.1:8099';
|
||
|
||
(async () => {
|
||
const browser = await chromium.launch({ headless: true });
|
||
const ctx = await browser.newContext();
|
||
const page = await ctx.newPage();
|
||
|
||
// 收集 console
|
||
const logs = [];
|
||
page.on('console', m => logs.push(`[${m.type()}] ${m.text()}`));
|
||
page.on('pageerror', e => logs.push(`[PAGEERROR] ${e.message}`));
|
||
|
||
console.log('=== 1. 访问首页,检查 renderer ===');
|
||
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 60000 });
|
||
await page.waitForTimeout(3000);
|
||
|
||
// 检查 renderer:canvaskit 有 <canvas> + flt-glass-pane;html 有 flutter-view 含 div
|
||
const canvasCount = await page.locator('canvas').count();
|
||
const fltGlass = await page.locator('flt-glass-pane').count();
|
||
const htmlView = await page.locator('flutter-view, .flutter-view').count();
|
||
console.log(`canvas 元素数: ${canvasCount}`);
|
||
console.log(`flt-glass-pane (canvaskit 标志): ${fltGlass}`);
|
||
console.log(`flutter-view: ${htmlView}`);
|
||
|
||
// body HTML 片段(判断 renderer)
|
||
const bodySnippet = await page.evaluate(() => document.body.innerHTML.slice(0, 400));
|
||
console.log(`body 片段: ${bodySnippet.slice(0, 200)}`);
|
||
|
||
console.log('\n=== 2. 访问登录页,检查输入框 DOM ===');
|
||
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 60000 });
|
||
await page.waitForTimeout(3000);
|
||
|
||
// Flutter web 输入框:canvaskit 会在聚焦时创建 <input>;检查有无 input
|
||
const inputCount = await page.locator('input').count();
|
||
console.log(`input 元素数: ${inputCount}`);
|
||
const inputs = await page.locator('input').evaluateAll(els =>
|
||
els.map(e => ({ type: e.type, placeholder: e.placeholder, ariaLabel: e.getAttribute('aria-label'), cls: e.className.slice(0, 40) }))
|
||
);
|
||
console.log('input 详情:', JSON.stringify(inputs).slice(0, 300));
|
||
|
||
// 检查 semantics(辅助功能树)
|
||
const semanticsRoles = await page.locator('[role="textbox"], [role="button"]').count();
|
||
console.log(`semantics (role=textbox/button): ${semanticsRoles}`);
|
||
|
||
console.log('\n=== 3. 检查存储(localStorage + IndexedDB)===');
|
||
const ls = await page.evaluate(() => {
|
||
return JSON.stringify(Object.keys(localStorage).reduce((o, k) => { o[k] = localStorage.getItem(k).slice(0, 100); return o; }, {}));
|
||
});
|
||
console.log(`localStorage: ${ls}`);
|
||
|
||
const idb = await page.evaluate(async () => {
|
||
const dbs = indexedDB.databases ? await indexedDB.databases() : [];
|
||
const result = [];
|
||
for (const db of dbs) {
|
||
result.push({ name: db.name, version: db.version });
|
||
}
|
||
return JSON.stringify(result);
|
||
});
|
||
console.log(`IndexedDB databases: ${idb}`);
|
||
|
||
console.log('\n=== 4. console 日志(前 10 条)===');
|
||
console.log(logs.slice(0, 10).join('\n'));
|
||
|
||
await browser.close();
|
||
})().catch(e => { console.error('探测失败:', e.message); process.exit(1); });
|