import automator from 'miniprogram-automator'; import fs from 'fs'; const WS = 'ws://127.0.0.1:9420'; const TIMEOUT = 15000; const SS_DIR = 'g:/hms/apps/miniprogram/screenshots'; const TABBAR_PAGES = ['pages/index/index', 'pages/health/index', 'pages/appointment/index', 'pages/article/index', 'pages/profile/index']; function withTimeout(promise, ms, label) { return Promise.race([promise, new Promise((_, r) => setTimeout(() => r(new Error(`${label} timeout`)), ms))]); } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } async function saveScreenshot(mp, name) { try { const ss = await withTimeout(mp.screenshot(), 20000, 'screenshot'); const ssPath = `${SS_DIR}/${name}.png`; if (Buffer.isBuffer(ss)) { fs.writeFileSync(ssPath, ss); } else { fs.writeFileSync(ssPath, Buffer.from(ss, 'base64')); } return true; } catch (e) { return false; } } async function main() { console.log('=== HMS 小程序验证 V3 ===\n'); if (!fs.existsSync(SS_DIR)) fs.mkdirSync(SS_DIR, { recursive: true }); const mp = await withTimeout(automator.connect({ wsEndpoint: WS }), TIMEOUT, 'connect'); console.log('[OK] 已连接\n'); // System info const info = await withTimeout(mp.systemInfo(), TIMEOUT, 'sys'); console.log(`设备: ${info.model} | SDK: ${info.SDKVersion} | 屏幕: ${info.screenWidth}x${info.screenHeight}\n`); // Test pages - tabBar pages first using switchTab, then non-tabBar using reLaunch const testPages = [ { path: '/pages/index/index', name: '首页', tabBar: true }, { path: '/pages/health/index', name: '健康中心', tabBar: true }, { path: '/pages/appointment/index', name: '预约列表', tabBar: true }, { path: '/pages/article/index', name: '资讯文章', tabBar: true }, { path: '/pages/profile/index', name: '个人中心', tabBar: true }, { path: '/pages/health/input/index', name: '健康数据录入' }, { path: '/pages/health/trend/index', name: '健康趋势' }, { path: '/pages/appointment/create/index', name: '创建预约' }, { path: '/pages/appointment/detail/index', name: '预约详情' }, { path: '/pages/article/detail/index', name: '文章详情' }, { path: '/pages/profile/family/index', name: '就诊人管理' }, { path: '/pages/profile/reports/index', name: '我的报告' }, { path: '/pages/profile/followups/index', name: '我的随访' }, { path: '/pages/profile/medication/index', name: '用药提醒' }, { path: '/pages/profile/settings/index', name: '设置' }, { path: '/pages/login/index', name: '登录页' }, { path: '/pages/legal/user-agreement', name: '用户协议' }, { path: '/pages/legal/privacy-policy', name: '隐私政策' }, ]; let pass = 0, fail = 0, ss = 0; for (const p of testPages) { try { if (p.tabBar) { await withTimeout(mp.switchTab(p.path), TIMEOUT, `switchTab ${p.path}`); } else { await withTimeout(mp.reLaunch(p.path), TIMEOUT, `reLaunch ${p.path}`); } await sleep(1500); const page = await withTimeout(mp.currentPage(), TIMEOUT, 'currentPage'); const ssOk = await saveScreenshot(mp, p.path.replace(/\//g, '_').replace(/^_/, '')); if (ssOk) ss++; console.log(` [OK] ${p.name} → ${page.path}${ssOk ? ' 📸' : ''}`); pass++; } catch (e) { console.log(` [FAIL] ${p.name}: ${e.message}`); fail++; // Try to recover connection try { await sleep(2000); await withTimeout(mp.currentPage(), 5000, 'recovery'); } catch { // Connection might be dead, try reconnecting console.log(' [RECOVERY] 尝试重新连接...'); try { const mp2 = await withTimeout(automator.connect({ wsEndpoint: WS }), 10000, 'reconnect'); Object.assign(mp, mp2); console.log(' [RECOVERY] 重新连接成功'); } catch { console.log(' [RECOVERY] 重新连接失败'); } } } } // Page data checks console.log('\n--- 页面数据检查 ---'); const dataPages = ['/pages/index/index', '/pages/login/index']; for (const dp of dataPages) { try { await withTimeout(mp.reLaunch(dp), TIMEOUT, `nav ${dp}`); await sleep(1500); const page = await withTimeout(mp.currentPage(), TIMEOUT, 'page'); const data = await withTimeout(page.data(), TIMEOUT, 'data'); console.log(` ${dp}: keys = ${Object.keys(data).join(', ')}`); } catch (e) { console.log(` ${dp}: ${e.message}`); } } console.log(`\n=== 结果: ${pass}/${testPages.length} 通过, ${fail} 失败, ${ss} 截图 ===`); try { await mp.close(); } catch {} } main().catch(err => { console.error('Fatal:', err.message); process.exit(1); });