405 lines
14 KiB
TypeScript
405 lines
14 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,
|
|
navigateToTimerPage,
|
|
addTimer,
|
|
deleteAllTimers,
|
|
navigateToFirmwarePage,
|
|
checkFirmwareVersion,
|
|
navigateToDeviceInfo,
|
|
getDeviceInfo,
|
|
scrollToAndTap,
|
|
waitForSource,
|
|
enterEditInfo,
|
|
addDeviceViaBLE,
|
|
isDeviceOnHomepage,
|
|
createScene,
|
|
executeSceneFromHomepage,
|
|
deleteScene,
|
|
ensureHomeTab,
|
|
} from '../../utils/common';
|
|
import * as dotenv from 'dotenv';
|
|
import * as path from 'path';
|
|
|
|
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
|
|
|
const deviceName = getDeviceName('fan', 'FAN_DEVICE');
|
|
|
|
// 必测项控制锚点: 无电池款 Circulator Fan 首页控制开关 BLE 15975#JBszgxRS / WiFi 15974#KNyzKhn6
|
|
const PROTO = process.env.PROTO === 'wifi' ? 'wifi' : 'ble';
|
|
const CTRL_FAN = PROTO === 'wifi' ? '[P0][ONES:15974#KNyzKhn6][wifi]' : '[P0][ONES:15975#JBszgxRS][ble]';
|
|
|
|
describe('Fan Control - 风扇控制页', () => {
|
|
let driver: DeviceDriver;
|
|
let reporter: TestReporter;
|
|
|
|
beforeAll(async () => {
|
|
driver = createDriver();
|
|
await driver.createSession();
|
|
reporter = new TestReporter('Fan_Control', driver.platform.toUpperCase());
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await driver.dismissPopupIfPresent();
|
|
await driver.goBackToHomepage();
|
|
await driver.dismissPopupIfPresent();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
reporter.generate();
|
|
await driver.destroySession();
|
|
});
|
|
|
|
async function enterFanControl(): Promise<void> {
|
|
let el = await driver.findElementRaw('name', deviceName);
|
|
if (!el) {
|
|
await driver.scrollDown(250);
|
|
await sleep(1000);
|
|
el = await driver.findElementRaw('name', deviceName);
|
|
}
|
|
if (!el) throw new Error(`找不到${deviceName}卡片`);
|
|
await driver.tapElement(el);
|
|
await sleep(3000);
|
|
}
|
|
|
|
it('打开开关', async () => {
|
|
const start = Date.now();
|
|
try {
|
|
await enterFanControl();
|
|
|
|
const powerEl = await driver.findElementRaw('name', 'Power') ||
|
|
await driver.findElementRaw('name', 'power') ||
|
|
await driver.findElementRaw('name', 'ON/OFF');
|
|
if (!powerEl) throw new Error('Power按钮未找到');
|
|
await driver.tapElement(powerEl);
|
|
await sleep(3000);
|
|
|
|
const source = await driver.getSource();
|
|
const isOn = source.includes('ON') || source.includes('Normal') || source.includes('Speed');
|
|
console.log('风扇开启:', isOn);
|
|
|
|
reporter.record(`${CTRL_FAN} 打开开关`, 'PASS', Date.now() - start, `Power已点击, ON=${isOn}`);
|
|
} catch (e: any) {
|
|
const ss = await driver.screenshot().catch(() => '');
|
|
reporter.record(`${CTRL_FAN} 打开开关`, 'FAIL', Date.now() - start, e.message, ss);
|
|
throw e;
|
|
}
|
|
});
|
|
|
|
it('切换模式', async () => {
|
|
const start = Date.now();
|
|
try {
|
|
await enterFanControl();
|
|
|
|
const sourceBefore = await driver.getSource();
|
|
const modesBefore = ['Normal', 'Natural', 'Sleep'].filter(m => sourceBefore.includes(m));
|
|
|
|
// Try tapping different mode buttons
|
|
const naturalEl = await driver.findElementRaw('name', 'Natural') ||
|
|
await driver.findElementRaw('name', 'Natural Wind');
|
|
const sleepEl = await driver.findElementRaw('name', 'Sleep') ||
|
|
await driver.findElementRaw('name', 'Sleep Mode');
|
|
const normalEl = await driver.findElementRaw('name', 'Normal') ||
|
|
await driver.findElementRaw('name', 'Normal Mode');
|
|
|
|
let tappedMode = '';
|
|
if (naturalEl) {
|
|
await driver.tapElement(naturalEl);
|
|
tappedMode = 'Natural';
|
|
} else if (sleepEl) {
|
|
await driver.tapElement(sleepEl);
|
|
tappedMode = 'Sleep';
|
|
} else if (normalEl) {
|
|
await driver.tapElement(normalEl);
|
|
tappedMode = 'Normal';
|
|
} else {
|
|
throw new Error('未找到模式按钮(Normal/Natural/Sleep)');
|
|
}
|
|
await sleep(3000);
|
|
|
|
const sourceAfter = await driver.getSource();
|
|
const modeChanged = sourceAfter.includes(tappedMode);
|
|
console.log(`切换模式: ${tappedMode}, 结果: ${modeChanged}`);
|
|
|
|
reporter.record('切换模式', 'PASS', Date.now() - start, `切换至${tappedMode}, changed=${modeChanged}`);
|
|
} 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 enterFanControl();
|
|
|
|
const minusEl = await driver.findElementRaw('name', '-') ||
|
|
await driver.findElementRaw('name', 'minus') ||
|
|
await driver.findElementRaw('name', 'speed down') ||
|
|
await driver.findElementRaw('name', 'Speed Down');
|
|
if (!minusEl) throw new Error('减速按钮未找到');
|
|
|
|
await driver.tapElement(minusEl);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
console.log('降低风速完成');
|
|
|
|
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 enterFanControl();
|
|
|
|
const plusEl = await driver.findElementRaw('name', '+') ||
|
|
await driver.findElementRaw('name', 'plus') ||
|
|
await driver.findElementRaw('name', 'speed up') ||
|
|
await driver.findElementRaw('name', 'Speed Up');
|
|
if (!plusEl) throw new Error('加速按钮未找到');
|
|
|
|
await driver.tapElement(plusEl);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
console.log('增加风速完成');
|
|
|
|
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 enterFanControl();
|
|
|
|
// Scroll down to find Night Light section
|
|
await driver.scrollDown(300);
|
|
await sleep(1000);
|
|
|
|
const nightLightEl = await driver.findElementRaw('name', 'Night Light') ||
|
|
await driver.findElementRaw('name', 'night light') ||
|
|
await driver.findElementRaw('name', 'Nightlight');
|
|
if (!nightLightEl) throw new Error('Night Light区域未找到');
|
|
|
|
const rect = await driver.getElementRect(nightLightEl);
|
|
// Swipe on brightness slider area (below the Night Light label)
|
|
const sliderY = rect.y + rect.height + 40;
|
|
await driver.swipe(rect.x + 50, sliderY, rect.x + 200, sliderY, 500);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
console.log('小夜灯亮度调节完成');
|
|
|
|
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 enterFanControl();
|
|
|
|
await driver.scrollDown(300);
|
|
await sleep(1000);
|
|
|
|
const nightLightEl = await driver.findElementRaw('name', 'Night Light') ||
|
|
await driver.findElementRaw('name', 'night light') ||
|
|
await driver.findElementRaw('name', 'Nightlight');
|
|
if (!nightLightEl) throw new Error('Night Light区域未找到');
|
|
|
|
const rect = await driver.getElementRect(nightLightEl);
|
|
// Tap the switch/toggle near Night Light (right side)
|
|
await driver.tap(rect.x + rect.width + 50, rect.y + rect.height / 2);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
const isOff = source.includes('OFF') || !source.includes('brightness');
|
|
console.log('小夜灯关闭:', isOff);
|
|
|
|
reporter.record('关闭小夜灯', 'PASS', Date.now() - start, `小夜灯OFF=${isOff}`);
|
|
} 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 enterFanControl();
|
|
|
|
await driver.scrollDown(300);
|
|
await sleep(1000);
|
|
|
|
const swingEl = await driver.findElementRaw('name', 'Horizontal Swing') ||
|
|
await driver.findElementRaw('name', 'Horizontal') ||
|
|
await driver.findElementRaw('name', 'H Swing');
|
|
if (!swingEl) throw new Error('Horizontal Swing未找到');
|
|
|
|
await driver.tapElement(swingEl);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
console.log('水平摆风已切换');
|
|
|
|
reporter.record('水平摆风', 'PASS', Date.now() - start, 'Horizontal Swing已点击');
|
|
} 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 enterFanControl();
|
|
|
|
await driver.scrollDown(300);
|
|
await sleep(1000);
|
|
|
|
const swingEl = await driver.findElementRaw('name', 'Swing') ||
|
|
await driver.findElementRaw('name', 'Auto Swing') ||
|
|
await driver.findElementRaw('name', 'Oscillation');
|
|
if (!swingEl) throw new Error('Swing/Auto Swing按钮未找到');
|
|
|
|
await driver.tapElement(swingEl);
|
|
await sleep(2000);
|
|
|
|
const source = await driver.getSource();
|
|
const isOn = source.includes('ON') || source.includes('Swing');
|
|
console.log('自动摆风开启:', isOn);
|
|
|
|
reporter.record('开启自动摆风', 'PASS', Date.now() - start, `Swing ON=${isOn}`);
|
|
} 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 enterFanControl();
|
|
|
|
const tapped = await scrollToAndTap(driver, 'Delay');
|
|
if (!tapped) throw new Error('Delay选项未找到');
|
|
await sleep(2000);
|
|
|
|
// Set delay time - confirm
|
|
const source = await driver.getSource();
|
|
const hasTimePicker = source.includes('hour') || source.includes('min') || source.includes('Hour') || source.includes('Min');
|
|
console.log('延迟设置页:', hasTimePicker);
|
|
|
|
// Tap confirm/save
|
|
const confirmEl = await driver.findElementRaw('name', 'Confirm') ||
|
|
await driver.findElementRaw('name', 'OK') ||
|
|
await driver.findElementRaw('name', 'Save');
|
|
if (confirmEl) {
|
|
await driver.tapElement(confirmEl);
|
|
await sleep(2000);
|
|
}
|
|
|
|
reporter.record('开启延迟', 'PASS', Date.now() - start, `Delay页面=${hasTimePicker}`);
|
|
} 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 enterFanControl();
|
|
|
|
const navOk = await navigateToTimerPage(driver);
|
|
expect(navOk).toBe(true);
|
|
await sleep(2000);
|
|
|
|
const added = await addTimer(driver);
|
|
expect(added).toBe(true);
|
|
|
|
const source = await driver.getSource();
|
|
const hasTimer = source.includes('Only once') || source.includes('Timer') || source.includes('Schedule');
|
|
console.log('定时器添加:', hasTimer);
|
|
|
|
reporter.record('定时器添加', 'PASS', Date.now() - start, `定时器添加成功, hasTimer=${hasTimer}`);
|
|
} 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 enterFanControl();
|
|
|
|
const navOk = await navigateToTimerPage(driver);
|
|
expect(navOk).toBe(true);
|
|
await sleep(2000);
|
|
|
|
const deleted = await deleteAllTimers(driver);
|
|
expect(deleted).toBe(true);
|
|
console.log('定时器已全部删除');
|
|
|
|
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 enterFanControl();
|
|
|
|
const powerEl = await driver.findElementRaw('name', 'Power') ||
|
|
await driver.findElementRaw('name', 'power') ||
|
|
await driver.findElementRaw('name', 'ON/OFF');
|
|
if (!powerEl) throw new Error('Power按钮未找到');
|
|
await driver.tapElement(powerEl);
|
|
await sleep(3000);
|
|
|
|
const source = await driver.getSource();
|
|
const isOff = source.includes('OFF') || source.includes('off') || source.includes('Disconnected');
|
|
console.log('风扇关闭:', isOff);
|
|
|
|
reporter.record(`${CTRL_FAN} 关闭开关`, 'PASS', Date.now() - start, `Power OFF=${isOff}`);
|
|
} catch (e: any) {
|
|
const ss = await driver.screenshot().catch(() => '');
|
|
reporter.record(`${CTRL_FAN} 关闭开关`, 'FAIL', Date.now() - start, e.message, ss);
|
|
throw e;
|
|
}
|
|
});
|
|
});
|