fix(runtime): e2e 发现的 3 个 bug 修复

- 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)
This commit is contained in:
2026-08-01 23:20:25 +08:00
parent 6d08db54a5
commit 944493a39b
195 changed files with 362929 additions and 3 deletions

68
tools/e2e/probe.js Normal file
View File

@@ -0,0 +1,68 @@
// 探测脚本:检查 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);
// 检查 renderercanvaskit 有 <canvas> + flt-glass-panehtml 有 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); });