appium-mac2-driver
Version:
XCTest-based Appium driver for macOS apps automation
216 lines (181 loc) • 7.24 kB
JavaScript
import _ from 'lodash';
import { BaseDriver, DeviceSettings } from 'appium/driver';
import WDA_MAC_SERVER from './wda-mac';
import { desiredCapConstraints } from './desired-caps';
import * as appManagemenetCommands from './commands/app-management';
import * as appleScriptCommands from './commands/applescript';
import * as executeCommands from './commands/execute';
import * as findCommands from './commands/find';
import * as gesturesCommands from './commands/gestures';
import * as navigationCommands from './commands/navigation';
import * as recordScreenCommands from './commands/record-screen';
import * as screenshotCommands from './commands/screenshots';
import * as sourceCommands from './commands/source';
import log from './logger';
import { newMethodMap } from './method-map';
import { executeMethodMap } from './execute-method-map';
import * as nativeScreenRecordingCommands from './commands/native-record-screen';
/** @type {import('@appium/types').RouteMatcher[]} */
const NO_PROXY = [
['GET', new RegExp('^/session/[^/]+/appium')],
['POST', new RegExp('^/session/[^/]+/appium')],
['POST', new RegExp('^/session/[^/]+/element/[^/]+/elements?$')],
['POST', new RegExp('^/session/[^/]+/elements?$')],
['POST', new RegExp('^/session/[^/]+/execute')],
['POST', new RegExp('^/session/[^/]+/execute/sync')],
['GET', new RegExp('^/session/[^/]+/timeouts$')],
['POST', new RegExp('^/session/[^/]+/timeouts$')],
];
export class Mac2Driver extends BaseDriver {
/** @type {boolean} */
isProxyActive;
/** @type {import('./wda-mac').WDAMacServer} */
wda;
/** @type {nativeScreenRecordingCommands.NativeVideoChunksBroadcaster} */
_videoChunksBroadcaster;
static newMethodMap = newMethodMap;
static executeMethodMap = executeMethodMap;
constructor (opts = {}) {
// @ts-ignore TODO: Make opts typed
super(opts);
this.desiredCapConstraints = desiredCapConstraints;
this.locatorStrategies = [
'id',
'name',
'accessibility id',
'xpath',
'class name',
'-ios predicate string',
'predicate string',
'-ios class chain',
'class chain',
];
this.resetState();
this.settings = new DeviceSettings({}, this.onSettingsUpdate.bind(this));
}
async onSettingsUpdate (key, value) {
return await this.wda.proxy.command('/appium/settings', 'POST', {
settings: {[key]: value}
});
}
resetState () {
// @ts-ignore This is ok
this.wda = null;
this.proxyReqRes = null;
this.isProxyActive = false;
this._videoChunksBroadcaster = new nativeScreenRecordingCommands.NativeVideoChunksBroadcaster(
this.eventEmitter, this.log
);
this._screenRecorder = null;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
proxyActive (sessionId) {
return this.isProxyActive;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getProxyAvoidList (sessionId) {
return NO_PROXY;
}
canProxy () {
return true;
}
async proxyCommand (url, method, body = null) {
return await this.wda.proxy.command(url, method, body);
}
// @ts-ignore We know WDA response should be ok
async getStatus () {
return await this.wda.proxy.command('/status', 'GET');
}
// needed to make image plugin work
async getWindowRect () {
return await this.wda.proxy.command('/window/rect', 'GET');
}
// @ts-ignore TODO: make args typed
async createSession (...args) {
// @ts-ignore TODO: make args typed
const [sessionId, caps] = await super.createSession(...args);
this.wda = WDA_MAC_SERVER;
try {
if (caps.prerun) {
if (!_.isString(caps.prerun.command) && !_.isString(caps.prerun.script)) {
throw new Error(`'prerun' capability value must either contain ` +
`'script' or 'command' entry of string type`);
}
log.info('Executing prerun AppleScript');
const output = await this.macosExecAppleScript(caps.prerun);
if (_.trim(output)) {
log.info(`Prerun script output: ${output}`);
}
}
await this.wda.startSession(caps, {
reqBasePath: this.basePath,
});
} catch (e) {
await this.deleteSession();
throw e;
}
this.proxyReqRes = this.wda.proxy.proxyReqRes.bind(this.wda.proxy);
this.isProxyActive = true;
return [sessionId, caps];
}
async deleteSession () {
await this._screenRecorder?.stop(true);
if (this._videoChunksBroadcaster.hasPublishers) {
try {
await this.wda.proxy.command('/wda/video/stop', 'POST', {});
} catch {}
await this._videoChunksBroadcaster.shutdown(5000);
}
await this.wda.stopSession();
if (this.opts.postrun) {
if (!_.isString(this.opts.postrun.command) && !_.isString(this.opts.postrun.script)) {
log.error(`'postrun' capability value must either contain ` +
`'script' or 'command' entry of string type`);
} else {
log.info('Executing postrun AppleScript');
try {
const output = await this.macosExecAppleScript(this.opts.postrun);
if (_.trim(output)) {
log.info(`Postrun script output: ${output}`);
}
} catch (e) {
log.error(e.message);
}
}
}
this.resetState();
await super.deleteSession();
}
macosLaunchApp = appManagemenetCommands.macosLaunchApp;
macosActivateApp = appManagemenetCommands.macosActivateApp;
macosTerminateApp = appManagemenetCommands.macosTerminateApp;
macosQueryAppState = appManagemenetCommands.macosQueryAppState;
macosExecAppleScript = appleScriptCommands.macosExecAppleScript;
execute = executeCommands.execute;
findElOrEls = findCommands.findElOrEls;
macosSetValue = gesturesCommands.macosSetValue;
macosClick = gesturesCommands.macosClick;
macosScroll = gesturesCommands.macosScroll;
macosSwipe = gesturesCommands.macosSwipe;
macosRightClick = gesturesCommands.macosRightClick;
macosHover = gesturesCommands.macosHover;
macosDoubleClick = gesturesCommands.macosDoubleClick;
macosClickAndDrag = gesturesCommands.macosClickAndDrag;
macosClickAndDragAndHold = gesturesCommands.macosClickAndDragAndHold;
macosKeys = gesturesCommands.macosKeys;
macosPressAndHold = gesturesCommands.macosPressAndHold;
macosTap = gesturesCommands.macosTap;
macosDoubleTap = gesturesCommands.macosDoubleTap;
macosPressAndDrag = gesturesCommands.macosPressAndDrag;
macosPressAndDragAndHold = gesturesCommands.macosPressAndDragAndHold;
macosDeepLink = navigationCommands.macosDeepLink;
startRecordingScreen = recordScreenCommands.startRecordingScreen;
stopRecordingScreen = recordScreenCommands.stopRecordingScreen;
macosStartNativeScreenRecording = nativeScreenRecordingCommands.macosStartNativeScreenRecording;
macosGetNativeScreenRecordingInfo = nativeScreenRecordingCommands.macosGetNativeScreenRecordingInfo;
macosStopNativeScreenRecording = nativeScreenRecordingCommands.macosStopNativeScreenRecording;
macosListDisplays = nativeScreenRecordingCommands.macosListDisplays;
macosScreenshots = screenshotCommands.macosScreenshots;
macosSource = sourceCommands.macosSource;
}
export default Mac2Driver;