-
-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Align the implementation of execute method map with other andro…
…id drivers (#780)
- Loading branch information
1 parent
2d528cb
commit d376a9b
Showing
6 changed files
with
73 additions
and
733 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,89 @@ | ||
import _ from 'lodash'; | ||
import {errors, PROTOCOLS} from 'appium/driver'; | ||
import {AndroidUiautomator2Driver} from '../driver'; | ||
|
||
const MOBILE_SCRIPT_NAME_PREFIX = 'mobile:'; | ||
import {AndroidDriver} from 'appium-android-driver'; | ||
|
||
/** | ||
* @override | ||
* @privateRemarks Because the "mobile" commands (execute methods) in this | ||
* driver universally accept an options object, this method will _not_ call | ||
* into `BaseDriver.executeMethod`. | ||
* @this {AndroidUiautomator2Driver} | ||
* @param {string} script | ||
* @param {any[]} [args] | ||
* @returns {Promise<any>} | ||
* @returns {import('@appium/types').StringRecord<string>} | ||
*/ | ||
export async function execute(script, args) { | ||
const mobileScriptName = toExecuteMethodName(script); | ||
const isWebContext = this.isWebContext(); | ||
if (mobileScriptName && isWebContext || !isWebContext) { | ||
if (mobileScriptName) { | ||
const executeMethodArgs = preprocessExecuteMethodArgs(args); | ||
this.log.info(`Executing method '${mobileScriptName}'`); | ||
return await this.executeMobile(mobileScriptName, executeMethodArgs); | ||
} | ||
// Just pass the script name through and let it fail with a proper error message | ||
return await this.executeMobile(`${script}`, {}); | ||
} | ||
const endpoint = | ||
/** @type {import('appium-chromedriver').Chromedriver} */ (this.chromedriver).jwproxy | ||
.downstreamProtocol === PROTOCOLS.MJSONWP | ||
? '/execute' | ||
: '/execute/sync'; | ||
return await /** @type {import('appium-chromedriver').Chromedriver} */ ( | ||
this.chromedriver | ||
).jwproxy.command(endpoint, 'POST', { | ||
script, | ||
args, | ||
}); | ||
export function mobileCommandsMapping() { | ||
const commonMapping = new AndroidDriver().mobileCommandsMapping.call(this); | ||
return { | ||
...commonMapping, | ||
dragGesture: 'mobileDragGesture', | ||
flingGesture: 'mobileFlingGesture', | ||
doubleClickGesture: 'mobileDoubleClickGesture', | ||
clickGesture: 'mobileClickGesture', | ||
longClickGesture: 'mobileLongClickGesture', | ||
pinchCloseGesture: 'mobilePinchCloseGesture', | ||
pinchOpenGesture: 'mobilePinchOpenGesture', | ||
swipeGesture: 'mobileSwipeGesture', | ||
scrollGesture: 'mobileScrollGesture', | ||
scrollBackTo: 'mobileScrollBackTo', | ||
scroll: 'mobileScroll', | ||
viewportScreenshot: 'mobileViewportScreenshot', | ||
viewportRect: 'mobileViewPortRect', | ||
|
||
deepLink: 'mobileDeepLink', | ||
|
||
acceptAlert: 'mobileAcceptAlert', | ||
dismissAlert: 'mobileDismissAlert', | ||
|
||
batteryInfo: 'mobileGetBatteryInfo', | ||
|
||
deviceInfo: 'mobileGetDeviceInfo', | ||
|
||
openNotifications: 'openNotifications', | ||
|
||
type: 'mobileType', | ||
replaceElementValue: 'mobileReplaceElementValue', | ||
|
||
getAppStrings: 'mobileGetAppStrings', | ||
|
||
installMultipleApks: 'mobileInstallMultipleApks', | ||
|
||
pressKey: 'mobilePressKey', | ||
|
||
screenshots: 'mobileScreenshots', | ||
|
||
scheduleAction: 'mobileScheduleAction', | ||
getActionHistory: 'mobileGetActionHistory', | ||
unscheduleAction: 'mobileUnscheduleAction', | ||
}; | ||
} | ||
|
||
/** | ||
* @override | ||
* @this {AndroidUiautomator2Driver} | ||
* @param {string} script Must be of the form `mobile: <something>`, which | ||
* differs from its parent class implementation. | ||
* @param {string} mobileCommand | ||
* @param {import('@appium/types').StringRecord} [opts={}] | ||
* @returns {Promise<any>} | ||
*/ | ||
export async function executeMobile(script, opts = {}) { | ||
if (!(script in AndroidUiautomator2Driver.executeMethodMap)) { | ||
const commandNames = _.map( | ||
_.keys(AndroidUiautomator2Driver.executeMethodMap), | ||
(value) => value.slice(8) | ||
); | ||
throw new errors.UnknownCommandError( | ||
`Unknown mobile command "${script}". ` + | ||
`Only ${commandNames.join(', ')} commands are supported.` | ||
); | ||
} | ||
const methodName = | ||
AndroidUiautomator2Driver.executeMethodMap[ | ||
/** @type {keyof import('../execute-method-map').Uiautomator2ExecuteMethodMap} */ (script) | ||
].command; | ||
|
||
return await /** @type {(opts?: any) => Promise<unknown>} */ (this[methodName])(opts); | ||
export async function executeMobile(mobileCommand, opts = {}) { | ||
return await new AndroidDriver().executeMobile.call(this, mobileCommand, preprocessOptions(opts)); | ||
} | ||
|
||
// #region Internal Helpers | ||
|
||
/** | ||
* Messages the arguments going into an execute method. | ||
* @remarks A similar method is implemented in `appium-xcuitest-driver`, but it | ||
* appears the methods in here handle unwrapping of `Element` objects, so we do | ||
* not do that here. | ||
* @param {readonly any[] | readonly [StringRecord] | Readonly<StringRecord>} [args] | ||
* Renames the deprecated `element` key to `elementId`. Historically, | ||
* all of the pre-Execute-Method-Map execute methods accepted an `element` _or_ and `elementId` param. | ||
* This assigns the `element` value to `elementId` if `elementId` is not already present. | ||
* | ||
* @param {import('@appium/types').StringRecord} [opts={}] | ||
* @internal | ||
* @returns {StringRecord<unknown>} | ||
* @returns {import('@appium/types').StringRecord|undefined} | ||
*/ | ||
function preprocessExecuteMethodArgs(args) { | ||
if (_.isArray(args)) { | ||
args = _.first(args); | ||
function preprocessOptions(opts = {}) { | ||
if (_.isPlainObject(opts) && !('elementId' in opts) && 'element' in opts) { | ||
opts.elementId = opts.element; | ||
delete opts.element; | ||
this.log.debug(`Replaced the obsolete 'element' key with 'elementId'`); | ||
} | ||
const executeMethodArgs = /** @type {StringRecord<unknown>} */ (args ?? {}); | ||
/** | ||
* Renames the deprecated `element` key to `elementId`. Historically, | ||
* all of the pre-Execute-Method-Map execute methods accepted an `element` _or_ and `elementId` param. | ||
* This assigns the `element` value to `elementId` if `elementId` is not already present. | ||
*/ | ||
if (!('elementId' in executeMethodArgs) && 'element' in executeMethodArgs) { | ||
executeMethodArgs.elementId = executeMethodArgs.element; | ||
delete executeMethodArgs.element; | ||
} | ||
|
||
return executeMethodArgs; | ||
} | ||
|
||
/** | ||
* Type guard to check if a script is an execute method. | ||
* @param {any} script | ||
* @internal | ||
* @returns {string?} | ||
*/ | ||
function toExecuteMethodName(script) { | ||
return _.startsWith(script, MOBILE_SCRIPT_NAME_PREFIX) | ||
? script.replace(new RegExp(`${MOBILE_SCRIPT_NAME_PREFIX}\\s*`), `${MOBILE_SCRIPT_NAME_PREFIX} `) | ||
: null; | ||
return opts; | ||
} | ||
|
||
// #endregion | ||
|
||
/** | ||
* @typedef {import('../uiautomator2').UiAutomator2Server} UiAutomator2Server | ||
* @typedef {import('appium-adb').ADB} ADB | ||
*/ | ||
|
||
/** | ||
* @template [T=any] | ||
* @typedef {import('@appium/types').StringRecord<T>} StringRecord | ||
* @typedef {import('../driver').AndroidUiautomator2Driver} AndroidUiautomator2Driver | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.