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

88
tools/e2e/run.js Normal file
View File

@@ -0,0 +1,88 @@
// e2e 测试:遍历公开路由,捕获 Flutter 错误print→console 的 CK_ERROR/CK_STACK
const { chromium } = require('playwright');
const BASE = 'http://127.0.0.1:8099';
// 公开路由(不需登录)。动态参数用合理默认值
const ROUTES = [
'/',
'/shop',
'/shop/310',
'/about-us',
'/contact-us',
'/contact-stores',
'/download',
'/blog/310',
'/view-blog/52',
'/igoshow-learn-more',
'/minipos-learn-more',
'/buy-service/1/pos',
'/forgot-password',
'/new-user',
'/privacy-policy',
'/return-policy',
'/service-policy',
'/end-user-license-agreement',
];
const results = [];
async function testRoute(browser, route) {
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
const page = await ctx.newPage();
const errors = [];
const ckStacks = [];
page.on('pageerror', e => errors.push(`PAGEERROR: ${e.message.slice(0, 200)}`));
page.on('console', m => {
const t = m.text();
if (t.startsWith('CK_ERROR:')) errors.push(t);
if (t.startsWith('CK_STACK:')) {
// 提取项目文件:行号
const proj = t.match(/flutter_wisetronic\/[^\s]+:\d+/g);
if (proj) ckStacks.push([...new Set(proj)].slice(0, 3));
}
});
try {
await page.goto(BASE + route, { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(5000); // 等 Flutter 渲染 + API
} catch (e) {
errors.push(`GOTO_ERR: ${e.message.slice(0, 100)}`);
}
const status = errors.length === 0 ? '✓ OK' : `${errors.length} 错误`;
console.log(`${status.padEnd(12)} ${route}`);
if (errors.length > 0) {
console.log(' 错误: ' + errors.slice(0, 3).join(' | ').slice(0, 250));
if (ckStacks.length > 0) console.log(' 位置: ' + JSON.stringify(ckStacks[0]));
}
results.push({ route, errors, ckStacks });
await ctx.close();
}
(async () => {
console.log(`Flutter e2e 测试:${ROUTES.length} 个公开路由\n`);
const browser = await chromium.launch({ headless: true });
for (const r of ROUTES) {
await testRoute(browser, r);
}
await browser.close();
// 汇总
const failed = results.filter(r => r.errors.length > 0);
console.log(`\n========== 汇总 ==========`);
console.log(`总计 ${results.length} 路由,${failed.length} 个有错误`);
if (failed.length > 0) {
console.log('\n失败路由 + 崩溃位置:');
const locMap = {};
for (const f of failed) {
const loc = f.ckStacks[0] ? f.ckStacks[0][0] : '(无堆栈)';
locMap[loc] = locMap[loc] || [];
locMap[loc].push(f.route);
}
for (const [loc, routes] of Object.entries(locMap)) {
console.log(` ${loc}`);
console.log(` 影响: ${routes.join(', ')}`);
}
}
})();