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, waitForSource } from '../../utils/common'; import * as dotenv from 'dotenv'; import * as path from 'path'; dotenv.config({ path: path.resolve(__dirname, '../../.env') }); const deviceName = getDeviceName('camera', 'CAMERA_DEVICE'); describe('Camera Recording - 摄像头录像回放', () => { let driver: DeviceDriver; let reporter: TestReporter; beforeAll(async () => { driver = createDriver(); await driver.createSession(); reporter = new TestReporter('Camera_Recording', driver.platform.toUpperCase()); }); beforeEach(async () => { await driver.dismissPopupIfPresent(); await driver.goBackToHomepage(); await driver.dismissPopupIfPresent(); }); afterAll(async () => { reporter.generate(); await driver.destroySession(); }); async function findCameraCard(): Promise { const predicates = [ `name CONTAINS "${deviceName}" AND type == "XCUIElementTypeCell"`, 'name CONTAINS "Camera" AND type == "XCUIElementTypeCell"', 'name CONTAINS "Pan Tilt" AND type == "XCUIElementTypeCell"', 'name CONTAINS "Indoor" 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]; } return null; } async function enterControlPage(): Promise { const cardId = await findCameraCard(); if (!cardId) throw new Error('找不到摄像头卡片'); await driver.tapElement(cardId); await sleep(3000); } async function tapShowBtn(): Promise { const size = await driver.getWindowSize(); await driver.tap(size.width / 2, size.height / 3); await sleep(1000); } // ==================== 截图 ==================== it('录像-截图', async () => { const start = Date.now(); try { await enterControlPage(); await tapShowBtn(); const photoEl = await driver.findElementRaw('name', 'Photo'); expect(photoEl).not.toBeNull(); await driver.tapElement(photoEl!); await sleep(2000); // Take second photo await tapShowBtn(); const photoEl2 = await driver.findElementRaw('name', 'Photo'); if (photoEl2) await driver.tapElement(photoEl2); await sleep(2000); reporter.record('录像-截图', 'PASS', Date.now() - start, '截图x2完成'); } catch (e: any) { reporter.record('录像-截图', 'FAIL', Date.now() - start, e.message); throw e; } }); // ==================== 录视频 ==================== it('录像-录视频', async () => { const start = Date.now(); try { await enterControlPage(); await tapShowBtn(); const videoEl = await driver.findElementRaw('name', 'Video'); expect(videoEl).not.toBeNull(); await driver.tapElement(videoEl!); await sleep(2000); // Verify recording let source = await driver.getSource(); const isRecording = source.includes('Recording') || source.includes('Stop') || source.includes('0:'); // Stop await tapShowBtn(); const videoEl2 = await driver.findElementRaw('name', 'Video'); if (videoEl2) await driver.tapElement(videoEl2); await sleep(2000); reporter.record('录像-录视频', 'PASS', Date.now() - start, `录制=${isRecording}, 停止成功`); } catch (e: any) { reporter.record('录像-录视频', 'FAIL', Date.now() - start, e.message); throw e; } }); // ==================== SD卡回放 ==================== it('SD卡回放事件查看', async () => { const start = Date.now(); try { await enterControlPage(); const playbackEl = await driver.findElementRaw('name', 'Playback'); if (!playbackEl) { reporter.record('SD卡回放', 'SKIP', Date.now() - start, '未找到Playback标签'); return; } await driver.tapElement(playbackEl); await sleep(3000); // Switch to SD card tab const sdEl = await driver.findElementRaw('name', 'SD Card'); if (sdEl) { await driver.tapElement(sdEl); await sleep(3000); } // Select first event const cells = await driver.findElementsRaw('class name', 'XCUIElementTypeCell'); if (cells.length > 0) { await driver.tapElement(cells[0]); await sleep(10000); const source = await driver.getSource(); const hasPlayback = source.includes('Play') || source.includes('0:') || source.includes('Video'); console.log('SD卡回放:', hasPlayback); reporter.record('SD卡回放', 'PASS', Date.now() - start, `SD卡回放=${hasPlayback}`); } else { reporter.record('SD卡回放', 'SKIP', Date.now() - start, '无SD卡事件记录'); } } catch (e: any) { reporter.record('SD卡回放', 'FAIL', Date.now() - start, e.message); 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); const recordingEl = await driver.findElementRaw('name', 'Recording'); if (recordingEl) { await driver.tapElement(recordingEl); await sleep(2000); } const typeEl = await driver.findElementRaw('name', 'Type') || await driver.findElementRaw('name', 'All Types'); if (typeEl) { await driver.tapElement(typeEl); await sleep(1500); const allEl = await driver.findElementRaw('name', 'All Types'); if (allEl) await driver.tapElement(allEl); await sleep(3000); } const source = await driver.getSource(); const hasAll = source.includes('All Types') || source.includes('Recording'); reporter.record('相册-所有类型', 'PASS', Date.now() - start, `All Types筛选=${hasAll}`); } catch (e: any) { reporter.record('相册-所有类型', 'FAIL', Date.now() - start, e.message); 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); const recordingEl = await driver.findElementRaw('name', 'Recording'); if (recordingEl) { await driver.tapElement(recordingEl); await sleep(2000); } const typeEl = await driver.findElementRaw('name', 'Type') || await driver.findElementRaw('name', 'All Types'); if (typeEl) { await driver.tapElement(typeEl); await sleep(1500); const photosEl = await driver.findElementRaw('name', 'Photos'); if (photosEl) await driver.tapElement(photosEl); await sleep(3000); } const source = await driver.getSource(); const hasPhotos = source.includes('Photos') || source.includes('Photo'); reporter.record('相册-照片', 'PASS', Date.now() - start, `Photos筛选=${hasPhotos}`); } catch (e: any) { reporter.record('相册-照片', 'FAIL', Date.now() - start, e.message); 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); const recordingEl = await driver.findElementRaw('name', 'Recording'); if (recordingEl) { await driver.tapElement(recordingEl); await sleep(2000); } const typeEl = await driver.findElementRaw('name', 'Type') || await driver.findElementRaw('name', 'All Types'); if (typeEl) { await driver.tapElement(typeEl); await sleep(1500); const videosEl = await driver.findElementRaw('name', 'Videos'); if (videosEl) await driver.tapElement(videosEl); await sleep(3000); } const source = await driver.getSource(); const hasVideos = source.includes('Videos') || source.includes('Video'); reporter.record('相册-视频', 'PASS', Date.now() - start, `Videos筛选=${hasVideos}`); } catch (e: any) { reporter.record('相册-视频', 'FAIL', Date.now() - start, e.message); 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); const recordingEl = await driver.findElementRaw('name', 'Recording'); if (recordingEl) { await driver.tapElement(recordingEl); await sleep(2000); } const editEl = await driver.findElementRaw('name', 'Edit'); if (!editEl) { reporter.record('相册选择删除', 'SKIP', Date.now() - start, '未找到Edit按钮'); return; } await driver.tapElement(editEl); await sleep(1500); // Select first item const cells = await driver.findElementsRaw('class name', 'XCUIElementTypeCell'); if (cells.length > 0) { await driver.tapElement(cells[0]); await sleep(500); } // Delete const deleteEl = await driver.findElementRaw('name', 'Delete'); if (deleteEl) { await driver.tapElement(deleteEl); await sleep(1000); const confirmEl = await driver.findElementRaw('name', 'Confirm'); if (confirmEl) await driver.tapElement(confirmEl); await sleep(3000); } // Done const doneEl = await driver.findElementRaw('name', 'Done'); if (doneEl) await driver.tapElement(doneEl); await sleep(1000); reporter.record('相册选择删除', 'PASS', Date.now() - start, '相册选择删除完成'); } catch (e: any) { reporter.record('相册选择删除', 'FAIL', Date.now() - start, e.message); 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); const recordingEl = await driver.findElementRaw('name', 'Recording'); if (recordingEl) { await driver.tapElement(recordingEl); await sleep(2000); } const editEl = await driver.findElementRaw('name', 'Edit'); if (!editEl) { reporter.record('相册全选删除', 'SKIP', Date.now() - start, '未找到Edit按钮'); return; } await driver.tapElement(editEl); await sleep(1500); // Select all const selectAllEl = await driver.findElementRaw('name', 'Select All'); if (selectAllEl) { await driver.tapElement(selectAllEl); await sleep(1000); } // Delete const deleteEl = await driver.findElementRaw('name', 'Delete'); if (deleteEl) { await driver.tapElement(deleteEl); await sleep(1000); const confirmEl = await driver.findElementRaw('name', 'Confirm'); if (confirmEl) await driver.tapElement(confirmEl); await sleep(5000); } const source = await driver.getSource(); const isEmpty = source.includes('No recording') || source.includes('No data') || source.includes('empty') || !source.includes('XCUIElementTypeCell'); console.log('相册清空:', isEmpty); reporter.record('相册全选删除', 'PASS', Date.now() - start, `相册全选删除, 清空=${isEmpty}`); } catch (e: any) { reporter.record('相册全选删除', 'FAIL', Date.now() - start, e.message); throw e; } }); });