diff --git a/README.md b/README.md index 24accd1c7..f9b1f8518 100644 --- a/README.md +++ b/README.md @@ -1161,6 +1161,99 @@ Values are dictionaries with the following properties: - `width`: Bar width (might be zero if the bar is not present in the system info output) - `height`: Bar height (might be zero if the bar is not present in the system info output) +### mobile: fingerprint + +Emulate [fingerprint](https://learn.microsoft.com/en-us/xamarin/android/platform/fingerprint-authentication/enrolling-fingerprint) on Android Emulator. Only works on API 23+. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +fingerprintId | number | yes | The value is the id for the finger that was "scanned". It is a unique integer that you assign for each virtual fingerprint. When the app is running you can run this same command each time the emulator prompts you for a fingerprint, you can run the adb command and pass it the fingerprintId to simulate the fingerprint scan. | 1 + +### mobile: sendSms + +Emulate sending an SMS to the given phone number. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +phoneNumber | string | yes | The phone number to send SMS to | 0123456789 +message | string | yes | The SMS message payload | Hello + +### mobile: gsmCall + +Emulate a GSM call to the given phone number. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +phoneNumber | string | yes | The phone number to call to | 0123456789 +action | call or accept or cancel or hold | yes | One of possible actions to take | accept + +### mobile: gsmSignal + +Emulate GSM signal strength change event. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +strength | 0 or 1 or 2 or 3 or 4 | yes | One of possible signal strength values, where 4 is the best signal. | 3 + +### mobile: gsmVoice + +Emulate a GSM call to the given phone number. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +state | on or off | yes | Voice state | off + +### mobile: powerAC + +Emulate AC power state change. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +state | on or off | yes | AC Power state | off + +### mobile: powerCapacity + +Emulate power capacity change. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +percent | 0 to 100 | yes | Percentage value in range [0, 100] | 50 + +### mobile: networkSpeed + +Emulate different network connection speed modes. Only works on emulators. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +speed | gsm or scsd or gprs or edge or umts or hsdpa or lte or evdo or full | yes | Mobile network speed mode name | edge + +### mobile: replaceElementValue + +Sends a text to the given element by replacing its previous content. Available since driver version 2.22 + +#### Arguments + +Name | Type | Required | Description | Example +--- | --- | --- | --- | --- +elementId | string | yes | Hexadecimal identifier of the destination text input | 123456-3456-3435-3453453 +text | string | yes | The text to enter. It could also contain Unicode characters. If the text ends with `\\n` (the backslash must be escaped, so the char is NOT translated into `0x0A`) then the Enter key press is going to be emulated after it is entered (the `\\n` substring itself will be cut off from the typed text). | yolo + ## Applications Management diff --git a/lib/commands/element.js b/lib/commands/element.js index 3a8699288..0fbd9674a 100644 --- a/lib/commands/element.js +++ b/lib/commands/element.js @@ -1,6 +1,7 @@ import _ from 'lodash'; import { util } from 'appium/support'; import { PROTOCOLS, W3C_ELEMENT_KEY } from 'appium/driver'; +import { requireArgs } from '../utils'; let commands = {}, helpers = {}, extensions = {}; @@ -121,6 +122,23 @@ commands.getElementRect = async function (elementId) { return await this.uiautomator2.jwproxy.command(`/element/${elementId}/rect`, 'GET'); }; +/** + * @typedef {Object} ReplaceValueOptions + * @property {string} elementId The id of the element whose content will be replaced + * @property {string} text The actual text to set + */ + +/** + * Sends text to the given element by replacing its previous content + * + * @param {ReplaceValueOptions} opts + * @throws {Error} If there was a faulre while setting the text + */ +commands.mobileReplaceElementValue = async function mobileReplaceElementValue (opts = {}) { + const {elementId, text} = requireArgs(['elementId', 'text'], opts); + return await this.uiautomator2.jwproxy.command(`/element/${elementId}/value`, 'POST', {text, replace: true}); +}; + Object.assign(extensions, commands, helpers); export { commands, helpers }; export default extensions; diff --git a/lib/commands/general.js b/lib/commands/general.js index 71205812f..cae02d0fb 100644 --- a/lib/commands/general.js +++ b/lib/commands/general.js @@ -100,7 +100,7 @@ extensions.executeMobile = async function (mobileCommand, opts = {}) { listSms: 'mobileListSms', type: 'mobileType', - sensorSet: 'sensorSet', + replaceElementValue: 'mobileReplaceElementValue', pushFile: 'mobilePushFile', pullFile: 'mobilePullFile', @@ -149,6 +149,16 @@ extensions.executeMobile = async function (mobileCommand, opts = {}) { getDisplayDensity: 'getDisplayDensity', getSystemBars: 'getSystemBars', + + fingerprint: 'mobilefingerprint', + sendSms: 'mobileSendSms', + gsmCall: 'mobileGsmCall', + gsmSignal: 'mobileGsmSignal', + gsmVoice: 'mobileGsmVoice', + powerAc: 'mobilePowerAc', + powerCapacity: 'mobilePowerCapacity', + networkSpeed: 'mobileNetworkSpeed', + sensorSet: 'sensorSet', }; if (!_.has(mobileCommandsMapping, mobileCommand)) { diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 000000000..3f677cc21 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,19 @@ +import _ from 'lodash'; +import { errors } from 'appium/driver'; + +/** + * Assert the presence of particular keys in the given object + * + * @template {Object} T + * @param {string|string[]} argNames one or more key names + * @param {T} opts the object to check + * @returns {T} the same given object + */ +export function requireArgs (argNames, opts = {}) { + for (const argName of (_.isArray(argNames) ? argNames : [argNames])) { + if (!_.has(opts, argName)) { + throw new errors.InvalidArgumentError(`'${argName}' argument must be provided`); + } + } + return opts; +} diff --git a/package.json b/package.json index d42f46dae..b06ad1919 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "dependencies": { "@babel/runtime": "^7.0.0", "appium-adb": "^9.11.0", - "appium-android-driver": "^5.10.4", + "appium-android-driver": "^5.11.0", "appium-chromedriver": "^5.3.1", "appium-uiautomator2-server": "^5.7.2", "asyncbox": "^2.3.1",