import { DeviceDriver, ElementLocator, Rect, Platform } from './types'; import { WDAHelper } from '../utils/wda-helper'; export class WDADriver implements DeviceDriver { readonly platform: Platform = 'ios'; private wda: WDAHelper; constructor(host = 'localhost', port = 8100) { this.wda = new WDAHelper(host, port); } async createSession(): Promise { await this.wda.createSession(); } async destroySession(): Promise { await this.wda.destroySession(); } async activateApp(appId: string): Promise { await this.wda.activateAppById(appId); } async findElement(locator: ElementLocator): Promise { if (!locator.ios) throw new Error(`Locator "${locator.name}" has no iOS strategy`); return this.wda.findElement(locator.ios.using, locator.ios.value); } async findElements(locator: ElementLocator): Promise { if (!locator.ios) throw new Error(`Locator "${locator.name}" has no iOS strategy`); return this.wda.findElements(locator.ios.using, locator.ios.value); } async findElementRaw(using: string, value: string): Promise { return this.wda.findElement(using, value); } async findElementsRaw(using: string, value: string): Promise { return this.wda.findElements(using, value); } async getElementRect(elementId: string): Promise { return this.wda.getElementRect(elementId); } async getElementAttribute(elementId: string, attr: string): Promise { return this.wda.getElementAttribute(elementId, attr); } async tap(x: number, y: number): Promise { return this.wda.tap(x, y); } async doubleTap(x: number, y: number): Promise { return this.wda.doubleTap(x, y); } async longPress(x: number, y: number, duration = 2): Promise { return this.wda.longPress(x, y, duration); } async tapElement(elementId: string): Promise { return this.wda.tapElement(elementId); } async clickElement(elementId: string): Promise { return this.wda.clickElement(elementId); } async typeText(elementId: string, text: string): Promise { return this.wda.typeText(elementId, text); } async clearText(elementId: string): Promise { return this.wda.clearText(elementId); } async swipe(fromX: number, fromY: number, toX: number, toY: number, duration = 0.5): Promise { return this.wda.swipe(fromX, fromY, toX, toY, duration); } async scrollDown(distance = 300): Promise { return this.wda.scrollDown(distance); } async scrollUp(distance = 300): Promise { return this.wda.scrollUp(distance); } async goBack(): Promise { await this.wda.tap(33, 69); } async getSource(): Promise { return this.wda.getSource(); } async getWindowSize(): Promise<{ width: number; height: number }> { return this.wda.getWindowSize(); } async screenshot(): Promise { return this.wda.screenshot(); } async tapByLocator(locator: ElementLocator): Promise { const elemId = await this.findElement(locator); if (!elemId) return false; await this.tapElement(elemId); return true; } async waitForElement(locator: ElementLocator, timeoutMs = 10000): Promise { const start = Date.now(); while (Date.now() - start < timeoutMs) { const elemId = await this.findElement(locator); if (elemId) return elemId; await new Promise((r) => setTimeout(r, 500)); } return null; } async isElementVisible(locator: ElementLocator): Promise { const elemId = await this.findElement(locator); if (!elemId) return false; const visible = await this.getElementAttribute(elemId, 'visible'); return visible === 'true' || visible === '1'; } async findBotCard(): Promise { return this.findDeviceCard('Bot'); } async findDeviceCard(deviceName: string): Promise { const predicates = [ `name CONTAINS "${deviceName}" AND type == "XCUIElementTypeCell"`, ]; for (const pred of predicates) { const elems = await this.findElementsRaw('predicate string', pred); if (elems.length > 0) return elems[0]; } return null; } async isOnHomepage(): Promise { return this.wda.isOnHomepage(); } async goBackToHomepage(): Promise { return this.wda.goBackToHomepage(); } async dismissPopupIfPresent(): Promise { const source = await this.getSource(); if (source.includes('XCUIElementTypeAlert')) { const dismissButtons = ['OK', 'Got it', 'Close', 'Cancel', 'Confirm', 'Allow', "Don't Allow", 'Later', 'Skip', 'Done']; for (const btn of dismissButtons) { const el = await this.findElementRaw('name', btn); if (el) { await this.tapElement(el); await new Promise(r => setTimeout(r, 1000)); return true; } } } if (source.includes('Upgrade') || source.includes("What's New")) { const dismissButtons = ['Close', 'Later', 'Skip', 'Not Now']; for (const btn of dismissButtons) { const el = await this.findElementRaw('name', btn); if (el) { await this.tapElement(el); await new Promise(r => setTimeout(r, 1000)); return true; } } } return false; } }