155 lines
5.1 KiB
TypeScript
155 lines
5.1 KiB
TypeScript
import { DeviceDriver } from '../../drivers/types';
|
|
import { sleep } from '../../utils/common';
|
|
import { getDeviceName } from '../../config/device.config';
|
|
import { execSync } from 'child_process';
|
|
|
|
const AIHUB_NAME = getDeviceName('aihub', 'AIHUB_NAME');
|
|
const PKG = 'com.theswitchbot.switchbot';
|
|
const ACTIVITY = `${PKG}/.index.ui.SplashActivity`;
|
|
|
|
export function isAndroid(driver: DeviceDriver): boolean {
|
|
return driver.platform === 'android';
|
|
}
|
|
|
|
export async function forceRestartApp(driver: DeviceDriver): Promise<void> {
|
|
if (!isAndroid(driver)) return;
|
|
try {
|
|
execSync(`adb shell am force-stop ${PKG}`);
|
|
await sleep(2000);
|
|
execSync(`adb shell am start -n ${ACTIVITY}`);
|
|
await sleep(10000);
|
|
await driver.dismissPopupIfPresent();
|
|
await sleep(2000);
|
|
await driver.dismissPopupIfPresent();
|
|
} catch (e) {
|
|
console.error('[forceRestartApp] error:', e);
|
|
}
|
|
}
|
|
|
|
export async function ensureAppOnHomepage(driver: DeviceDriver): Promise<boolean> {
|
|
try {
|
|
const src = await driver.getSource();
|
|
if (src.includes('All Devices') || src.includes('content-desc="Home"')
|
|
|| (src.includes('Home') && !src.includes('Motion Detection') && !src.includes('Extended Display'))) {
|
|
return true;
|
|
}
|
|
} catch { /* session may be dead */ }
|
|
|
|
// Try goBackToHomepage first
|
|
try {
|
|
await driver.goBackToHomepage();
|
|
await sleep(3000);
|
|
await driver.dismissPopupIfPresent();
|
|
const src = await driver.getSource();
|
|
if (src.includes('All Devices') || src.includes('content-desc="Home"')) return true;
|
|
} catch { /* ignore */ }
|
|
|
|
// Force restart as last resort
|
|
await forceRestartApp(driver);
|
|
try {
|
|
const src = await driver.getSource();
|
|
return src.includes('All Devices') || src.includes('content-desc="Home"')
|
|
|| src.includes('Home');
|
|
} catch { return false; }
|
|
}
|
|
|
|
export async function enterHubFunctionPage(driver: DeviceDriver): Promise<boolean> {
|
|
const src = await driver.getSource();
|
|
if (src.includes('Cameras') && src.includes('AI Events')) return true;
|
|
|
|
const onHome = await ensureAppOnHomepage(driver);
|
|
if (!onHome) return false;
|
|
|
|
if (isAndroid(driver)) {
|
|
const card = await (driver as any).findDeviceCard(AIHUB_NAME);
|
|
if (!card) {
|
|
console.log('[enterHubFunctionPage] Hub card not found, trying scroll');
|
|
for (let i = 0; i < 3; i++) {
|
|
await driver.scrollDown(400);
|
|
await sleep(2000);
|
|
const retryCard = await (driver as any).findDeviceCard(AIHUB_NAME);
|
|
if (retryCard) {
|
|
await driver.tapElement(retryCard);
|
|
await sleep(6000);
|
|
await driver.dismissPopupIfPresent();
|
|
const s = await driver.getSource();
|
|
if (s.includes('Cameras') || s.includes('AI Events')) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
await driver.tapElement(card);
|
|
await sleep(6000);
|
|
await driver.dismissPopupIfPresent();
|
|
const s = await driver.getSource();
|
|
return s.includes('Cameras') || s.includes('AI Events');
|
|
}
|
|
|
|
// iOS
|
|
for (let scroll = 0; scroll <= 5; scroll++) {
|
|
let hubEl = await driver.findElementRaw('predicate string',
|
|
`name CONTAINS "${AIHUB_NAME}" AND type == "XCUIElementTypeCell"`);
|
|
if (!hubEl) {
|
|
hubEl = await driver.findElementRaw('predicate string', `label CONTAINS "${AIHUB_NAME}"`);
|
|
}
|
|
if (hubEl) {
|
|
await driver.tapElement(hubEl);
|
|
await sleep(5000);
|
|
await driver.dismissPopupIfPresent();
|
|
const s = await driver.getSource();
|
|
if (s.includes('Cameras') || s.includes('AI Events')) return true;
|
|
}
|
|
if (scroll < 5) {
|
|
await driver.swipe(195, 650, 195, 300, 0.5);
|
|
await sleep(1500);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export async function enterHubSettings(driver: DeviceDriver): Promise<boolean> {
|
|
const src = await driver.getSource();
|
|
if (src.includes('Motion Detection') || src.includes('Firmware')
|
|
|| src.includes('Do Not Disturb') || src.includes('Extended Display')
|
|
|| src.includes('Local Storage')) {
|
|
return true;
|
|
}
|
|
|
|
const inHub = await enterHubFunctionPage(driver);
|
|
if (!inHub) return false;
|
|
|
|
const gearX = isAndroid(driver) ? 999 : 361;
|
|
const gearY = isAndroid(driver) ? 175 : 70;
|
|
await driver.tap(gearX, gearY);
|
|
await sleep(5000);
|
|
|
|
const settingSrc = await driver.getSource();
|
|
return settingSrc.includes('Motion Detection') || settingSrc.includes('Firmware')
|
|
|| settingSrc.includes('Do Not Disturb') || settingSrc.includes('Wi-Fi');
|
|
}
|
|
|
|
export async function waitForLoading(driver: DeviceDriver, maxWait = 30000): Promise<void> {
|
|
const start = Date.now();
|
|
while (Date.now() - start < maxWait) {
|
|
const s = await driver.getSource();
|
|
if (!s.includes('Loading') && !s.includes('In progress')) return;
|
|
await sleep(3000);
|
|
}
|
|
}
|
|
|
|
export async function robustBeforeEach(driver: DeviceDriver): Promise<void> {
|
|
try {
|
|
await driver.dismissPopupIfPresent();
|
|
} catch {
|
|
// Session might be dead - recreate
|
|
try { await driver.destroySession(); } catch { /* ignore */ }
|
|
await driver.createSession();
|
|
await sleep(5000);
|
|
await forceRestartApp(driver);
|
|
}
|
|
}
|
|
|
|
export async function robustBeforeAll(driver: DeviceDriver): Promise<void> {
|
|
await forceRestartApp(driver);
|
|
}
|