112 lines
3.2 KiB
TypeScript
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);
|
|
}
|