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('osc', 'OSC_DEVICE'); describe('OSC Recording - 户外摄像头录像回放', () => { let driver: DeviceDriver; let reporter: TestReporter; let screenWidth = 390; let screenHeight = 844; beforeAll(async () => { driver = createDriver(); await driver.createSession(); reporter = new TestReporter('OSC_Recording', 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 findCameraCard(): Promise { if (driver.platform === 'ios') { const predicates = [ `name CONTAINS "${deviceName}" AND type == "XCUIElementTypeCell"`, 'name CONTAINS "OSC" AND type == "XCUIElementTypeCell"', 'name CONTAINS "Outdoor" AND type == "XCUIElementTypeCell"', 'name CONTAINS "Spotlight" 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("OSC")'); if (el2) return el2; } return null; } async function enterControlPage(): Promise { const cardId = await findCameraCard(); if (!cardId) throw new Error('找不到OSC设备卡片'); await driver.tapElement(cardId); await sleep(5000); } it('查看录像回放', async () => { const start = Date.now(); try { await enterControlPage(); // Tap Playback tab const playbackEl = await driver.findElementRaw('name', 'Playback'); if (!playbackEl) { reporter.record('查看录像回放', 'SKIP', Date.now() - start, '未找到Playback标签'); return; } await driver.tapElement(playbackEl); await sleep(3000); // Verify timeline is displayed const source = await driver.getSource(); const hasTimeline = source.includes('Playback') || source.includes('Timeline') || source.includes('SD Card') || source.includes('Recording') || source.includes('Cloud') || source.includes('0:'); console.log('录像回放页面:', hasTimeline); expect(hasTimeline).toBe(true); reporter.record('查看录像回放', 'PASS', Date.now() - start, `录像回放页面加载=${hasTimeline}`); } 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 playbackEl = await driver.findElementRaw('name', 'Playback'); if (!playbackEl) { reporter.record('播放录像片段', 'SKIP', Date.now() - start, '未找到Playback标签'); return; } await driver.tapElement(playbackEl); await sleep(3000); // Try tapping on timeline area (bottom half of the screen where timeline sits) // Timeline is usually in the lower portion of the screen const timelineY = screenHeight * 0.7; await driver.tap(screenWidth / 2, timelineY); await sleep(5000); // Verify playing indicator const source = await driver.getSource(); const isPlaying = source.includes('Play') || source.includes('0:') || source.includes('KB/S') || source.includes('Playback') || !source.includes('Disconnected'); console.log('录像播放状态:', isPlaying); // Also try SD Card tab if available const sdEl = await driver.findElementRaw('name', 'SD Card'); if (sdEl) { await driver.tapElement(sdEl); await sleep(3000); // Tap first event if available 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(5000); const sourceAfter = await driver.getSource(); const playingFromSD = sourceAfter.includes('Play') || sourceAfter.includes('0:') || sourceAfter.includes('Video'); console.log('SD卡回放:', playingFromSD); } } reporter.record('播放录像片段', 'PASS', Date.now() - start, `录像播放=${isPlaying}`); } catch (e: any) { const ss = await driver.screenshot().catch(() => ''); reporter.record('播放录像片段', 'FAIL', Date.now() - start, e.message, ss); throw e; } }); });