import { HubShowDriver, createHubShowDriver } from '../../drivers/hubshow-driver'; import { sleep } from '../../utils/common'; /** * AI Hub Show 固件测试 — 导航辅助函数 * * Hub Show 是基于 Android 的带屏设备,通过 adb 直连设备屏幕进行 UI 自动化。 * 设备本机有安防首页、事件列表、回放、摄像头实时、门铃等页面。 */ export { createHubShowDriver }; export async function wakeUpDevice(driver: HubShowDriver): Promise { const src = await driver.getSource(); if (src.includes('安防') || src.includes('主页') || src.includes('全部事件')) return; // 待机屏特征: 只有日期/天气信息 await driver.tap(540, 500); await sleep(1500); } export async function waitForLoading(driver: HubShowDriver, maxWait = 20000): Promise { const start = Date.now(); while (Date.now() - start < maxWait) { const s = await driver.getSource(); if (!s.includes('Loading') && !s.includes('加载中')) return; await sleep(2000); } } export async function ensureOnSecurityPage(driver: HubShowDriver): Promise { await wakeUpDevice(driver); const src = await driver.getSource(); // 安防页特征: 含"全部事件"或"回放"或("Security" + 摄像头相关) if (src.includes('全部事件') || src.includes('回放')) return true; if (src.includes('All Events') || src.includes('Playback')) return true; if ((src.includes('Security') || src.includes('安防')) && (src.includes('Camera') || src.includes('摄像机'))) return true; // Try navigating to security page - Hub Show main screen should have security entry const secEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("安防")'); if (secEl) { await driver.tapElement(secEl); await sleep(3000); await waitForLoading(driver); return true; } // Try English label const secElEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Security")'); if (secElEn) { await driver.tapElement(secElEn); await sleep(3000); await waitForLoading(driver); return true; } // Go back to home and retry await driver.goBack(); await sleep(2000); const retry = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("安防")'); if (retry) { await driver.tapElement(retry); await sleep(3000); return true; } return false; } export async function ensureOnEventList(driver: HubShowDriver): Promise { const src = await driver.getSource(); // 已在事件列表: 含筛选栏(人物/事件类型/设备) 或 有时间戳+删除按钮(列表视图) if (src.includes('事件类型') && (src.includes('人物') || src.includes('设备'))) return true; if (src.includes('Type') && (src.includes('Person') || src.includes('Device'))) return true; if (src.includes('删除') && /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(src)) return true; if (src.includes('编辑') && /\d{2}:\d{2}:\d{2}/.test(src) && !src.includes('全部事件')) return true; // Navigate to security page first const onSec = await ensureOnSecurityPage(driver); if (!onSec) return false; // 安防页有"全部事件"入口,点击进入事件列表 const allEventsEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("全部事件")'); if (allEventsEl) { await driver.tapElement(allEventsEl); await sleep(3000); await waitForLoading(driver); return true; } const allEventsEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("All Events")'); if (allEventsEn) { await driver.tapElement(allEventsEn); await sleep(3000); await waitForLoading(driver); return true; } return false; } export async function enterPlaybackPage(driver: HubShowDriver): Promise { const src = await driver.getSource(); if (src.includes('回放') || src.includes('Playback')) return true; const onSec = await ensureOnSecurityPage(driver); if (!onSec) return false; const playbackEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("回放")'); if (playbackEl) { await driver.tapElement(playbackEl); await sleep(3000); await waitForLoading(driver); return true; } const playbackEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Playback")'); if (playbackEn) { await driver.tapElement(playbackEn); await sleep(3000); await waitForLoading(driver); return true; } return false; } export async function enterCameraLive(driver: HubShowDriver, cameraName?: string): Promise { const onSec = await ensureOnSecurityPage(driver); if (!onSec) return false; // Tap on camera live feed area (depends on layout) if (cameraName) { const camEl = await driver.findElementRaw('-android uiautomator', `new UiSelector().textContains("${cameraName}")`); if (camEl) { await driver.tapElement(camEl); await sleep(3000); await waitForLoading(driver); const src = await driver.getSource(); return src.includes('实时') || src.includes('Live') || src.includes('警报') || src.includes('Alarm'); } } return false; } export async function enterDoorbellLive(driver: HubShowDriver): Promise { const onSec = await ensureOnSecurityPage(driver); if (!onSec) return false; const doorbellEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Doorbell")'); if (!doorbellEl) { const doorbellZh = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("门铃")'); if (!doorbellZh) return false; await driver.tapElement(doorbellZh); } else { await driver.tapElement(doorbellEl); } await sleep(3000); await waitForLoading(driver); const src = await driver.getSource(); return src.includes('门铃') || src.includes('Doorbell') || src.includes('快捷回复'); } export async function openFilterDialog(driver: HubShowDriver, filterType: 'date' | 'person' | 'type' | 'device'): Promise { const onEvents = await ensureOnEventList(driver); if (!onEvents) return false; const filterLabels: Record = { date: ['日期', 'Date'], person: ['人物', 'Person'], type: ['类型', 'Type', '事件类型'], device: ['设备', 'Device'], }; const labels = filterLabels[filterType] || []; for (const label of labels) { const el = await driver.findElementRaw('-android uiautomator', `new UiSelector().textContains("${label}")`); if (el) { await driver.tapElement(el); await sleep(2000); return true; } } return false; } export async function switchToTileView(driver: HubShowDriver): Promise { const onEvents = await ensureOnEventList(driver); if (!onEvents) return false; // Look for view switch button (grid/tile icon) const switchEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().descriptionContains("平铺")'); if (switchEl) { await driver.tapElement(switchEl); await sleep(2000); return true; } const switchEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().descriptionContains("Tile")'); if (switchEn) { await driver.tapElement(switchEn); await sleep(2000); return true; } return false; } export async function enterEditMode(driver: HubShowDriver): Promise { const editEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("编辑")'); if (editEl) { await driver.tapElement(editEl); await sleep(1500); return true; } const editEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Edit")'); if (editEn) { await driver.tapElement(editEn); await sleep(1500); return true; } return false; } export async function enterDailyReport(driver: HubShowDriver): Promise { const onSec = await ensureOnSecurityPage(driver); if (!onSec) return false; const reportEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("家居日报")'); if (reportEl) { await driver.tapElement(reportEl); await sleep(3000); await waitForLoading(driver); return true; } const reportEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Smart Report")'); if (reportEn) { await driver.tapElement(reportEn); await sleep(3000); await waitForLoading(driver); return true; } return false; } export function logPageSource(src: string): void { const texts: string[] = []; const textRe = /text="([^"]{1,100})"/g; let m; while ((m = textRe.exec(src)) !== null) { if (!texts.includes(m[1])) texts.push(m[1]); } console.log('Page texts:', texts.slice(0, 30).join(' | ')); }