AI_UIAutomation/tests/aihubshow/hubshow-setup.helper.ts

249 lines
8.7 KiB
TypeScript

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<void> {
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<void> {
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<boolean> {
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<boolean> {
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<boolean> {
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<boolean> {
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<boolean> {
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<boolean> {
const onEvents = await ensureOnEventList(driver);
if (!onEvents) return false;
const filterLabels: Record<string, string[]> = {
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<boolean> {
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<boolean> {
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<boolean> {
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(' | '));
}