AI_UIAutomation/utils/common/element.helper.ts

112 lines
3.2 KiB
TypeScript

import { DeviceDriver } from '../../drivers/types';
export function sleep(ms: number): Promise<void> {
return new Promise(r => setTimeout(r, ms));
}
/**
* 诊断:打印当前页面上的设备卡名(找不到目标设备时调,方便定位 = 真没这设备,还是名字/状态变了/还没渲染)。
* Android 取 nameText/nameTextMeter 节点文本;iOS 取 XCUIElementTypeCell 的 name。失败只告警,不抛。
*/
export async function logVisibleDeviceCards(driver: DeviceDriver, context: string): Promise<void> {
try {
const src = await driver.getSource();
let names: string[] = [];
if (driver.platform === 'android') {
for (const n of src.split('<')) {
if (!/resource-id="[^"]*\/(nameText|nameTextMeter)"/.test(n)) continue;
const t = (n.match(/text="([^"]*)"/) || [])[1];
if (t && t.trim()) names.push(t.trim());
}
} else {
names = (src.match(/XCUIElementTypeCell[^>]*?name="([^"]+)"/g) || [])
.map((m) => (m.match(/name="([^"]+)"/) || [])[1]).filter(Boolean) as string[];
}
names = [...new Set(names)];
console.log(`[诊断]${context} 当前页设备卡(${names.length}): ${names.slice(0, 50).join(' | ') || '(无)'}`);
} catch (e: any) {
console.log(`[诊断]${context} 取设备卡列表失败: ${e.message}`);
}
}
export async function waitForElement(
driver: DeviceDriver,
using: string,
value: string,
timeout = 10000
): Promise<string | null> {
const start = Date.now();
while (Date.now() - start < timeout) {
const el = await driver.findElementRaw(using, value);
if (el) return el;
await sleep(1000);
}
return null;
}
export async function waitForSource(
driver: DeviceDriver,
keyword: string,
timeout = 10000
): Promise<boolean> {
const start = Date.now();
while (Date.now() - start < timeout) {
const src = await driver.getSource();
if (src.includes(keyword)) return true;
await sleep(1000);
}
return false;
}
export async function scrollUntilFound(
driver: DeviceDriver,
using: string,
value: string,
maxScrolls = 5,
scrollDistance = 300
): Promise<string | null> {
for (let i = 0; i < maxScrolls; i++) {
const el = await driver.findElementRaw(using, value);
if (el) return el;
await driver.scrollDown(scrollDistance);
await sleep(800);
}
return null;
}
export async function tapWithRetry(
driver: DeviceDriver,
using: string,
value: string,
retries = 3
): Promise<boolean> {
for (let i = 0; i < retries; i++) {
try {
const el = await driver.findElementRaw(using, value);
if (el) {
await driver.tapElement(el);
return true;
}
} catch { /* stale element, retry */ }
await sleep(500);
}
return false;
}
export async function sourceContains(driver: DeviceDriver, keyword: string): Promise<boolean> {
const src = await driver.getSource();
return src.includes(keyword);
}
export async function findElementOnScreen(
driver: DeviceDriver,
keyword: string
): Promise<boolean> {
let src = await driver.getSource();
if (src.includes(keyword)) return true;
await driver.scrollDown(300);
await sleep(800);
src = await driver.getSource();
return src.includes(keyword);
}