362 lines
13 KiB
TypeScript
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;
|
|
}
|
|
});
|
|
});
|