// 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(', ')}`); } } })();