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:
88
tools/e2e/run.js
Normal file
88
tools/e2e/run.js
Normal 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(', ')}`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user