UNPKG

appium-chromedriver

Version:
115 lines (107 loc) 3.88 kB
import {system, util} from '@appium/support'; import {retryInterval} from 'asyncbox'; import {exec} from 'teen_process'; import {CHROMEDRIVER_STATES} from '../constants'; import type {ChromedriverCommandContext} from './types'; const VERSION_PATTERN = /([\d.]+)/; /** * Builds command-line arguments for the Chromedriver subprocess. */ export function buildChromedriverArgs(this: ChromedriverCommandContext): string[] { const args = [`--port=${this.proxyPort}`]; if (this.adb?.adbPort) { args.push(`--adb-port=${this.adb.adbPort}`); } if (Array.isArray(this.cmdArgs)) { args.push(...this.cmdArgs); } if (this.logPath) { args.push(`--log-path=${this.logPath}`); } if (this.disableBuildCheck) { args.push('--disable-build-check'); } args.push('--verbose'); return args; } /** * Retrieves Chromedriver `/status` payload through the active proxy. */ export async function getStatus(this: ChromedriverCommandContext): Promise<any> { return await this.jwproxy.command('/status', 'GET'); } /** * Polls Chromedriver until it reports ready and captures runtime metadata. */ export async function waitForOnline(this: ChromedriverCommandContext): Promise<void> { const self = this as ChromedriverCommandContext & { getStatus: () => Promise<any>; }; let chromedriverStopped = false; await retryInterval(20, 200, async () => { if (this.state === CHROMEDRIVER_STATES.STOPPED) { chromedriverStopped = true; return; } const status = await self.getStatus(); if (!util.isPlainObject(status) || !status.ready) { throw new Error(`The response to the /status API is not valid: ${JSON.stringify(status)}`); } const statusPayload = status as Record<string, any>; this._onlineStatus = statusPayload; const versionMatch = VERSION_PATTERN.exec(statusPayload.build?.version ?? ''); if (versionMatch) { this._driverVersion = versionMatch[1]; this.log.info(`Chromedriver version: ${this._driverVersion}`); } else { this.log.info('Chromedriver version cannot be determined from the /status API response'); } }); if (chromedriverStopped) { throw new Error('ChromeDriver crashed during startup.'); } } /** * Cleans up stale Chromedriver processes and leftover adb forwarded ports. */ export async function killAll(this: ChromedriverCommandContext): Promise<void> { const cmd = system.isWindows() ? 'wmic' : 'pkill'; const args = system.isWindows() ? [ 'process', 'where', `commandline like '%chromedriver.exe%--port=${this.proxyPort}%'`, 'delete', ] : ['-15', '-f', `${this.chromedriver}.*--port=${this.proxyPort}`]; this.log.debug(`Killing any old chromedrivers, running: ${cmd} ${args.join(' ')}`); try { await exec(cmd, args); this.log.debug('Successfully cleaned up old chromedrivers'); } catch { this.log.info('No old chromedrivers seem to exist'); } if (this.adb) { const udidIndex = this.adb.executable.defaultArgs.findIndex((item: string) => item === '-s'); const udid = udidIndex > -1 ? this.adb.executable.defaultArgs[udidIndex + 1] : null; if (udid) { this.log.debug(`Cleaning this device's adb forwarded port socket connections: ${udid}`); } else { this.log.debug(`Cleaning any old adb forwarded port socket connections`); } try { for (const conn of await this.adb.getForwardList()) { if (!(conn.includes('webview_devtools') && (!udid || conn.includes(udid)))) { continue; } const params = conn.split(/\s+/); if (params.length > 1) { await this.adb.removePortForward(params[1].replace(/[\D]*/, '')); } } } catch (e) { const err = e as Error; this.log.warn(`Unable to clean forwarded ports. Error: '${err.message}'. Continuing.`); } } }