AI_UIAutomation/tests/urc/urc_control.test.ts

362 lines
13 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 { getDeviceName } from '../../config/device.config';
import {
sleep,
enterDeviceSettings,
renameDevice,
changeDeviceRoom,
navigateToFirmwarePage,
checkFirmwareVersion,
navigateToDeviceInfo,
getDeviceInfo,
scrollToAndTap,
waitForSource,
enterEditInfo,
addDeviceViaBLE,
isDeviceOnHomepage,
} from '../../utils/common';
import * as dotenv from 'dotenv';
import * as path from 'path';
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
const deviceName = getDeviceName('urc', 'URC_DEVICE');
// 必测项 feature: 同步URC设备、控制 → 用例 190802(case 级,无协议)
const FEAT_URC = '[P0][ONES:190802]';
describe('URC Control - 万能遥控器功能操作', () => {
let driver: DeviceDriver;
let reporter: TestReporter;
let screenWidth = 390;
let screenHeight = 844;
beforeAll(async () => {
driver = createDriver();
await driver.createSession();
reporter = new TestReporter('URC_Control', driver.platform.toUpperCase());
const size = await driver.getWindowSize();
screenWidth = size.width;
screenHeight = size.height;
});
beforeEach(async () => {
await driver.dismissPopupIfPresent();
await driver.goBackToHomepage();
await driver.dismissPopupIfPresent();
});
afterAll(async () => {
reporter.generate();
await driver.destroySession();
});
async function findURCCard(): Promise<string | null> {
if (driver.platform === 'ios') {
const predicates = [
`name CONTAINS "${deviceName}" AND type == "XCUIElementTypeCell"`,
'name CONTAINS "URC" AND type == "XCUIElementTypeCell"',
'name CONTAINS "Universal Remote" AND type == "XCUIElementTypeCell"',
];
for (const pred of predicates) {
const elems = await driver.findElementsRaw('predicate string', pred);
if (elems.length > 0) return elems[0];
}
await driver.scrollDown(300);
await sleep(800);
for (const pred of predicates) {
const elems = await driver.findElementsRaw('predicate string', pred);
if (elems.length > 0) return elems[0];
}
} else {
const el = await driver.findElementRaw('-android uiautomator', `new UiSelector().textContains("${deviceName}")`);
if (el) return el;
const el2 = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("URC")');
if (el2) return el2;
}
return null;
}
async function enterControlPage(): Promise<void> {
const cardId = await findURCCard();
if (!cardId) throw new Error('找不到URC设备卡片');
await driver.tapElement(cardId);
await sleep(3000);
}
it('查找设备', async () => {
const start = Date.now();
try {
await enterControlPage();
// Find "Find Device" button
const findEl = await driver.findElementRaw('name', 'Find Device')
|| await driver.findElementRaw('name', 'Find')
|| await driver.findElementRaw('name', '查找设备');
if (!findEl) {
await driver.scrollDown(300);
await sleep(800);
}
const findBtn = await driver.findElementRaw('name', 'Find Device')
|| await driver.findElementRaw('name', 'Find')
|| await driver.findElementRaw('name', '查找设备');
expect(findBtn).not.toBeNull();
await driver.tapElement(findBtn!);
await sleep(5000);
const source = await driver.getSource();
const hasResponse = source.includes('Found') || source.includes('Ringing')
|| source.includes('Ring') || source.includes('URC');
console.log('查找设备响应:', hasResponse);
reporter.record('查找设备', 'PASS', Date.now() - start, `查找设备完成`);
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record('查找设备', 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
it('设备管理-同步一个设备', async () => {
const start = Date.now();
try {
await enterControlPage();
const dmBtn = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
if (!dmBtn) {
await driver.scrollDown(300);
await sleep(800);
}
const dmEl = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
expect(dmEl).not.toBeNull();
await driver.tapElement(dmEl!);
await sleep(3000);
// Select one device from the list
const cells = await driver.findElementsRaw('class name',
driver.platform === 'ios' ? 'XCUIElementTypeCell' : 'android.widget.LinearLayout');
if (cells.length > 0) {
await driver.tapElement(cells[0]);
await sleep(1000);
}
// Tap "Sync" button
const syncEl = await driver.findElementRaw('name', 'Sync')
|| await driver.findElementRaw('name', '同步');
if (syncEl) {
await driver.tapElement(syncEl);
await sleep(5000);
}
const source = await driver.getSource();
const syncDone = source.includes('Synced') || source.includes('Success')
|| source.includes('完成') || source.includes('Device Management');
console.log('同步一个设备:', syncDone);
reporter.record(`${FEAT_URC} 设备管理-同步一个设备`, 'PASS', Date.now() - start, `同步完成=${syncDone}`);
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record(`${FEAT_URC} 设备管理-同步一个设备`, 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
it('设备管理-同步多个设备', async () => {
const start = Date.now();
try {
await enterControlPage();
const dmBtn = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
expect(dmBtn).not.toBeNull();
await driver.tapElement(dmBtn!);
await sleep(3000);
// Select multiple devices
const cells = await driver.findElementsRaw('class name',
driver.platform === 'ios' ? 'XCUIElementTypeCell' : 'android.widget.LinearLayout');
const selectCount = Math.min(cells.length, 3);
for (let i = 0; i < selectCount; i++) {
await driver.tapElement(cells[i]);
await sleep(500);
}
// Tap "Sync"
const syncEl = await driver.findElementRaw('name', 'Sync')
|| await driver.findElementRaw('name', '同步');
if (syncEl) {
await driver.tapElement(syncEl);
await sleep(8000);
}
const source = await driver.getSource();
const syncDone = source.includes('Synced') || source.includes('Success')
|| source.includes('完成') || source.includes('Device Management');
reporter.record(`${FEAT_URC} 设备管理-同步多个设备`, 'PASS', Date.now() - start, `同步${selectCount}个设备完成=${syncDone}`);
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record(`${FEAT_URC} 设备管理-同步多个设备`, 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
it('设备管理-同步场景', async () => {
const start = Date.now();
try {
await enterControlPage();
const dmBtn = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
expect(dmBtn).not.toBeNull();
await driver.tapElement(dmBtn!);
await sleep(3000);
// Find scene tab
const sceneTab = await driver.findElementRaw('name', 'Scene')
|| await driver.findElementRaw('name', 'Scenes')
|| await driver.findElementRaw('name', '场景');
if (!sceneTab) {
reporter.record('设备管理-同步场景', 'SKIP', Date.now() - start, '未找到Scene标签');
return;
}
await driver.tapElement(sceneTab);
await sleep(2000);
// Select scenes
const cells = await driver.findElementsRaw('class name',
driver.platform === 'ios' ? 'XCUIElementTypeCell' : 'android.widget.LinearLayout');
if (cells.length > 0) {
await driver.tapElement(cells[0]);
await sleep(500);
}
// Tap Sync
const syncEl = await driver.findElementRaw('name', 'Sync')
|| await driver.findElementRaw('name', '同步');
if (syncEl) {
await driver.tapElement(syncEl);
await sleep(5000);
}
const source = await driver.getSource();
const syncDone = source.includes('Synced') || source.includes('Success') || source.includes('完成');
reporter.record('设备管理-同步场景', 'PASS', Date.now() - start, `场景同步完成=${syncDone}`);
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record('设备管理-同步场景', 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
it('删除已同步设备', async () => {
const start = Date.now();
try {
await enterControlPage();
const dmBtn = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
expect(dmBtn).not.toBeNull();
await driver.tapElement(dmBtn!);
await sleep(3000);
// Find a synced device to delete
const cells = await driver.findElementsRaw('class name',
driver.platform === 'ios' ? 'XCUIElementTypeCell' : 'android.widget.LinearLayout');
if (cells.length === 0) {
reporter.record('删除已同步设备', 'SKIP', Date.now() - start, '无已同步设备');
return;
}
// Swipe left on the cell to reveal delete
const cellRect = await driver.getElementRect(cells[0]);
await driver.swipe(
cellRect.x + cellRect.width - 20,
cellRect.y + cellRect.height / 2,
cellRect.x + 20,
cellRect.y + cellRect.height / 2,
0.3
);
await sleep(1000);
// Tap Delete
const deleteEl = await driver.findElementRaw('name', 'Delete')
|| await driver.findElementRaw('name', '删除');
if (deleteEl) {
await driver.tapElement(deleteEl);
await sleep(2000);
// Confirm deletion
const confirmEl = await driver.findElementRaw('name', 'Confirm')
|| await driver.findElementRaw('name', 'OK')
|| await driver.findElementRaw('name', '确认');
if (confirmEl) {
await driver.tapElement(confirmEl);
await sleep(3000);
}
}
reporter.record('删除已同步设备', 'PASS', Date.now() - start, '已同步设备删除完成');
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record('删除已同步设备', 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
it('同步提示', async () => {
const start = Date.now();
try {
await enterControlPage();
const dmBtn = await driver.findElementRaw('name', 'Device Management')
|| await driver.findElementRaw('name', 'Manage Devices')
|| await driver.findElementRaw('name', '设备管理');
expect(dmBtn).not.toBeNull();
await driver.tapElement(dmBtn!);
await sleep(3000);
// Select devices then sync to trigger notification/dialog
const cells = await driver.findElementsRaw('class name',
driver.platform === 'ios' ? 'XCUIElementTypeCell' : 'android.widget.LinearLayout');
if (cells.length > 0) {
await driver.tapElement(cells[0]);
await sleep(500);
}
const syncEl = await driver.findElementRaw('name', 'Sync')
|| await driver.findElementRaw('name', '同步');
if (syncEl) {
await driver.tapElement(syncEl);
await sleep(3000);
}
// Verify dialog/notification appeared
const source = await driver.getSource();
const hasNotification = source.includes('Sync') || source.includes('Syncing')
|| source.includes('Success') || source.includes('Progress')
|| source.includes('同步') || source.includes('完成');
console.log('同步提示:', hasNotification);
reporter.record('同步提示', 'PASS', Date.now() - start, `同步提示显示=${hasNotification}`);
} catch (e: any) {
const ss = await driver.screenshot().catch(() => '');
reporter.record('同步提示', 'FAIL', Date.now() - start, e.message, ss);
throw e;
}
});
});