120 lines
5.7 KiB
TypeScript
120 lines
5.7 KiB
TypeScript
import { describe, it, beforeAll, afterAll, beforeEach, expect } from 'vitest';
|
|
import { DeviceDriver } from '../../drivers/types';
|
|
import { createDriver } from '../../drivers/factory';
|
|
import { TestReporter } from '../../utils/test-reporter';
|
|
import { sleep, onesCtrl, setupResilientHooks, findHomeCard } from '../../utils/common';
|
|
import * as dotenv from 'dotenv';
|
|
import * as path from 'path';
|
|
|
|
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
|
|
|
// Relay Switch 首页卡片控制(参照 plug_card):Relay Switch 卡**无首页内联开关**(点卡任意处直接进功能页) →
|
|
// "首页控制" = 首页找到卡片 + 从首页点卡进设备页发起开/关。功能页:大圆形电源键(中心 ~540,525)+ 状态 "On"/"Off"。
|
|
const deviceName = process.env.RELAY_SWITCH_DEVICE || 'Relay Switch 1';
|
|
const CTRL = onesCtrl('plug', deviceName) || '[P0]'; // 基础 Relay Switch 1 → step41 Relay1(A1TLxsFw)
|
|
|
|
describe('Relay Switch Card - 首页卡片控制(进设备页 开/关)', () => {
|
|
let driver: DeviceDriver;
|
|
let reporter: TestReporter;
|
|
setupResilientHooks(() => driver);
|
|
const isIOS = () => driver.platform === 'ios';
|
|
|
|
beforeAll(async () => {
|
|
driver = createDriver();
|
|
await driver.createSession();
|
|
reporter = new TestReporter('RelaySwitch_Card', driver.platform.toUpperCase());
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await driver.dismissPopupIfPresent();
|
|
await driver.goBackToHomepage();
|
|
await sleep(500);
|
|
await driver.dismissPopupIfPresent();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
reporter.generate();
|
|
await driver.destroySession();
|
|
});
|
|
|
|
function readState(src: string): 'On' | 'Off' | 'unknown' {
|
|
if (isIOS()) { const m = src.match(/(?:name|label|value)="(On|Off)"/); return m ? (m[1] as any) : 'unknown'; }
|
|
for (const m of src.matchAll(/text="(On|Off)"[^>]*bounds="\[\d+,(\d+)\]\[\d+,\d+\]"/g)) {
|
|
const y = +m[2]; if (y > 250 && y < 820) return m[1] as any;
|
|
}
|
|
return 'unknown';
|
|
}
|
|
async function tapPower(): Promise<boolean> {
|
|
if (!isIOS()) {
|
|
const cont = await driver.findElementRaw('-android uiautomator',
|
|
'new UiSelector().clickable(true).childSelector(new UiSelector().textMatches("On|Off"))').catch(() => null);
|
|
if (cont) { await driver.tapElement(cont); return true; }
|
|
const wh = await driver.getWindowSize().catch(() => ({ width: 1080, height: 2400 }));
|
|
await driver.tap(Math.round(wh.width * 0.5), Math.round(wh.height * 0.219)); return true;
|
|
}
|
|
const p = await driver.findElementRaw('predicate string', 'name == "Power" OR name == "On" OR name == "Off"').catch(() => null);
|
|
if (p) { await driver.tapElement(p); return true; }
|
|
const wh = await driver.getWindowSize().catch(() => ({ width: 390, height: 844 }));
|
|
await driver.tap(Math.round(wh.width * 0.5), Math.round(wh.height * 0.28)); return true;
|
|
}
|
|
async function waitState(want: 'On' | 'Off'): Promise<'On' | 'Off' | 'unknown'> {
|
|
let st = readState(await driver.getSource());
|
|
for (let i = 0; i < 12 && st !== want; i++) { await sleep(1500); st = readState(await driver.getSource()); }
|
|
return st;
|
|
}
|
|
// 从首页点卡进设备页(无弹窗,点卡直进)
|
|
async function enterFromCard(): Promise<boolean> {
|
|
const card = await findHomeCard(driver, deviceName);
|
|
if (!card) return false;
|
|
await driver.tapElement(card); await sleep(2200);
|
|
for (let i = 0; i < 8; i++) { if (readState(await driver.getSource()) !== 'unknown') return true; await sleep(1000); }
|
|
return readState(await driver.getSource()) !== 'unknown';
|
|
}
|
|
|
|
it(`首页找到 ${deviceName} 卡片`, { timeout: 60000 }, async () => {
|
|
const start = Date.now();
|
|
try {
|
|
const card = await findHomeCard(driver, deviceName);
|
|
expect(card).not.toBeNull();
|
|
const rect = await driver.getElementRect(card!);
|
|
expect(rect.width).toBeGreaterThan(0);
|
|
reporter.record('首页找到Relay Switch卡片', 'PASS', Date.now() - start, `位置(${rect.x},${rect.y}) ${rect.width}x${rect.height}`);
|
|
} catch (e: any) {
|
|
const ss = await driver.screenshot().catch(() => '');
|
|
reporter.record('首页找到Relay Switch卡片', 'FAIL', Date.now() - start, e.message, ss); throw e;
|
|
}
|
|
});
|
|
|
|
it(`${CTRL} 首页控制${deviceName}(开+关)`, { timeout: 120000 }, async () => {
|
|
const start = Date.now();
|
|
try {
|
|
if (!(await enterFromCard())) {
|
|
// 首页有该开关却进不去设备页 = 未正确执行 → FAIL(交给 catch);首页确无该开关(未添加/本平台无实体)→ 合法 SKIP。
|
|
await driver.goBackToHomepage().catch(() => {}); await sleep(1200);
|
|
if (await findHomeCard(driver, deviceName).catch(() => null)) throw new Error('首页进设备页失败(首页有该开关但进不去,未正确执行)');
|
|
reporter.record(`${CTRL} 首页控制${deviceName}`, 'SKIP', Date.now() - start, '首页无该开关(未添加/本平台无实体),跳过');
|
|
return;
|
|
}
|
|
const s0 = readState(await driver.getSource());
|
|
console.log(`[RSCard] 初始: ${s0}`);
|
|
|
|
const target1 = s0 === 'On' ? 'Off' : 'On';
|
|
expect(await tapPower()).toBe(true);
|
|
const s1 = await waitState(target1);
|
|
console.log(`[RSCard] 操作1后: ${s1}(目标${target1})`);
|
|
expect(s1).toBe(target1);
|
|
|
|
const target2 = target1 === 'On' ? 'Off' : 'On';
|
|
await tapPower();
|
|
const s2 = await waitState(target2);
|
|
console.log(`[RSCard] 操作2后: ${s2}(目标${target2})`);
|
|
expect(s2).toBe(target2);
|
|
|
|
reporter.record(`${CTRL} 首页控制${deviceName}`, 'PASS', Date.now() - start, `首页发起开/关均生效(${s0}→${s1}→${s2})`);
|
|
} catch (e: any) {
|
|
const ss = await driver.screenshot().catch(() => '');
|
|
reporter.record(`${CTRL} 首页控制${deviceName}`, 'FAIL', Date.now() - start, e.message, ss); throw e;
|
|
}
|
|
});
|
|
});
|