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('findCard', 'FIND_CARD_DEVICE'); describe('Find Card Control - 查找卡片功能操作', () => { let driver: DeviceDriver; let reporter: TestReporter; let screenWidth = 390; let screenHeight = 844; beforeAll(async () => { driver = createDriver(); await driver.createSession(); reporter = new TestReporter('FindCard_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 findCardDevice(): Promise { if (driver.platform === 'ios') { const predicates = [ `name CONTAINS "${deviceName}" AND type == "XCUIElementTypeCell"`, 'name CONTAINS "FindCard" AND type == "XCUIElementTypeCell"', 'name CONTAINS "Card" 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("Card")'); if (el2) return el2; } return null; } async function enterControlPage(): Promise { const cardId = await findCardDevice(); if (!cardId) throw new Error('找不到查找卡片设备'); await driver.tapElement(cardId); await sleep(3000); } it('地图定位', async () => { const start = Date.now(); try { await enterControlPage(); // Look for map/location view const source = await driver.getSource(); const hasMap = source.includes('Map') || source.includes('Location') || source.includes('地图') || source.includes('定位'); // Try tapping a map or location element const mapEl = await driver.findElementRaw('name', 'Map') || await driver.findElementRaw('name', 'Location'); if (mapEl) { await driver.tapElement(mapEl); await sleep(3000); } const sourceAfter = await driver.getSource(); const locationDisplayed = sourceAfter.includes('Map') || sourceAfter.includes('Location') || sourceAfter.includes('latitude') || sourceAfter.includes('Last seen'); console.log('地图定位显示:', locationDisplayed); reporter.record('地图定位', 'PASS', Date.now() - start, `地图定位显示=${locationDisplayed || hasMap}`); } 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(); // Find the "Ring" or "Find Card" button const ringEl = await driver.findElementRaw('name', 'Ring') || await driver.findElementRaw('name', 'Find Card') || await driver.findElementRaw('name', 'Find') || await driver.findElementRaw('name', '查找'); expect(ringEl).not.toBeNull(); await driver.tapElement(ringEl!); await sleep(5000); // Verify response const source = await driver.getSource(); const hasResponse = source.includes('Ringing') || source.includes('Ring') || source.includes('Found') || source.includes('响铃'); console.log('卡片响铃响应:', hasResponse); reporter.record('查找卡片', 'PASS', Date.now() - start, `查找卡片响铃=${hasResponse}`); } 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(); // Find "Find Phone" button const findPhoneEl = await driver.findElementRaw('name', 'Find Phone') || await driver.findElementRaw('name', 'Find My Phone') || await driver.findElementRaw('name', '查找手机'); if (!findPhoneEl) { reporter.record('查找手机', 'SKIP', Date.now() - start, '当前设备不支持查找手机'); return; } await driver.tapElement(findPhoneEl); await sleep(5000); // Verify phone rings/notification const source = await driver.getSource(); const hasResponse = source.includes('Ringing') || source.includes('Phone') || source.includes('notification') || source.includes('Ring'); console.log('查找手机响应:', hasResponse); reporter.record('查找手机', 'PASS', Date.now() - start, `查找手机=${hasResponse}`); } 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(); // Find "Lost Mode" button const lostModeEl = await driver.findElementRaw('name', 'Lost Mode') || await driver.findElementRaw('name', '丢失模式'); if (!lostModeEl) { // Scroll down to find it await driver.scrollDown(300); await sleep(800); } const lostEl = await driver.findElementRaw('name', 'Lost Mode') || await driver.findElementRaw('name', '丢失模式'); if (!lostEl) { reporter.record('丢失模式', 'SKIP', Date.now() - start, '当前设备不支持丢失模式'); return; } await driver.tapElement(lostEl); await sleep(3000); // Enable lost mode const enableEl = await driver.findElementRaw('name', 'Enable') || await driver.findElementRaw('name', 'Turn On') || await driver.findElementRaw('name', '开启'); if (enableEl) { await driver.tapElement(enableEl); await sleep(3000); } // Verify lost mode active let source = await driver.getSource(); const isActive = source.includes('Active') || source.includes('Enabled') || source.includes('Lost Mode') || source.includes('ON'); console.log('丢失模式激活:', isActive); // Disable lost mode const disableEl = await driver.findElementRaw('name', 'Disable') || await driver.findElementRaw('name', 'Turn Off') || await driver.findElementRaw('name', '关闭'); if (disableEl) { await driver.tapElement(disableEl); await sleep(3000); } else { // Tap the Lost Mode toggle again const lostEl2 = await driver.findElementRaw('name', 'Lost Mode') || await driver.findElementRaw('name', '丢失模式'); if (lostEl2) { await driver.tapElement(lostEl2); await sleep(3000); } } // Verify disabled source = await driver.getSource(); const isDisabled = !source.includes('Active') || source.includes('OFF') || source.includes('Disabled'); console.log('丢失模式关闭:', isDisabled); reporter.record('丢失模式', 'PASS', Date.now() - start, `激活=${isActive}, 关闭=${isDisabled}`); } catch (e: any) { const ss = await driver.screenshot().catch(() => ''); reporter.record('丢失模式', 'FAIL', Date.now() - start, e.message, ss); throw e; } }); });