import { describe, it, beforeAll, afterAll, expect } from 'vitest'; import { execSync } from 'child_process'; import { DeviceDriver } from '../../drivers/types'; import { createDriver } from '../../drivers/factory'; import { TestReporter } from '../../utils/test-reporter'; import { setupResilientHooks } from "../../utils/common"; import { sleep, ensureHomeTab, onesPlatform, createAutomation, verifyAutomationExecuted, deleteAutomation, createScene, executeSceneFromHomepage, verifySceneInLogs, deleteScene, signInWithEmail, isLoggedIn, } from '../../utils/common'; import * as dotenv from 'dotenv'; import * as path from 'path'; dotenv.config({ path: path.resolve(__dirname, '../../.env') }); const ANCHOR = `${onesPlatform(15976)} 场景操作`; // P0:场景操作验证(① 自动化 ② 场景) /** 读安卓设备当前时间 [h, m]。 */ function deviceNow(): [number, number] { const out = execSync('adb shell date +%H:%M').toString().trim().split(':'); return [parseInt(out[0], 10), parseInt(out[1], 10)]; } /** 在 [h,m] 上加 addMin 分钟,返回 [h,m](跨小时进位)。 */ function plusMin(h: number, m: number, addMin: number): [number, number] { const t = (h * 60 + m + addMin) % (24 * 60); return [Math.floor(t / 60), t % 60]; } describe('Platform - 场景操作(自动化 + 场景)', () => { let driver: DeviceDriver; let reporter: TestReporter; setupResilientHooks(() => driver); const autoName = `AutoOp${Date.now() % 100000}`; const sceneName = `SceneOp${Date.now() % 100000}`; beforeAll(async () => { driver = createDriver(); await driver.createSession(); reporter = new TestReporter('Platform_SceneOp', driver.platform.toUpperCase()); if (!(await isLoggedIn(driver))) await signInWithEmail(driver); }); afterAll(async () => { // 兜底清理 try { await deleteAutomation(driver, autoName); } catch { /**/ } try { await ensureHomeTab(driver); await deleteScene(driver, sceneName); } catch { /**/ } reporter.generate(); await driver.destroySession(); }); it(`${ANCHOR} ① 自动化创建与执行`, { timeout: 360000 }, async () => { const start = Date.now(); try { // 定时设为设备时间 + 2 分钟(创建较快,留出创建耗时后约 1 分钟内触发) const [nh, nm] = deviceNow(); const [th, tm] = plusMin(nh, nm, 2); console.log(`设备时间 ${nh}:${nm} → 定时 ${th}:${tm}`); const created = await createAutomation(driver, { name: autoName, deviceKeyword: 'Bot 14', targetHour: th, targetMinute: tm, action: 'Turns off' }); expect(created).toBe(true); // 等到点(目标时间 + 40s 让引擎触发+落日志) const deadlineMin = th * 60 + tm; for (let i = 0; i < 60; i++) { const [ch, cm] = deviceNow(); if (ch * 60 + cm > deadlineMin) break; await sleep(10000); } await sleep(40000); const executed = await verifyAutomationExecuted(driver, autoName); expect(executed).toBe(true); await deleteAutomation(driver, autoName); reporter.record(`${ANCHOR} ①自动化`, 'PASS', Date.now() - start, `自动化 ${autoName} 定时${th}:${tm} 触发并有日志,已删除`); } catch (e: any) { const ss = await driver.screenshot().catch(() => ''); reporter.record(`${ANCHOR} ①自动化`, 'FAIL', Date.now() - start, e.message, ss); throw e; } }); it(`${ANCHOR} ② 场景创建与执行`, { timeout: 180000 }, async () => { const start = Date.now(); try { // 场景动作与自动化(Bot Turns off)区分:Bot Turns on(同设备不同动作) const created = await createScene(driver, { name: sceneName, deviceKeyword: 'Bot 14', action: 'Turns on' }); expect(created).toBe(true); await ensureHomeTab(driver); const executed = await executeSceneFromHomepage(driver, sceneName); expect(executed).toBe(true); await sleep(6000); await driver.goBackToHomepage(); const hasLog = await verifySceneInLogs(driver, sceneName); expect(hasLog).toBe(true); await deleteScene(driver, sceneName); reporter.record(`${ANCHOR} ②场景`, 'PASS', Date.now() - start, `场景 ${sceneName} 执行并有日志,已删除`); } catch (e: any) { const ss = await driver.screenshot().catch(() => ''); reporter.record(`${ANCHOR} ②场景`, 'FAIL', Date.now() - start, e.message, ss); throw e; } }); });