Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: Add support of executeMethodMap #982

Merged
merged 1 commit into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 68 additions & 42 deletions lib/commands/app-management.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {util} from '@appium/support';
import {waitForCondition, longSleep} from 'asyncbox';
import _ from 'lodash';
import {requireArgs} from '../utils';
import {EOL} from 'node:os';
import B from 'bluebird';

Expand Down Expand Up @@ -33,11 +32,12 @@ export async function isAppInstalled(appId, opts = {}) {

/**
* @this {AndroidDriver}
* @param {import('./types').IsAppInstalledOpts} opts
* @param {string} appId Application package identifier
* @param {string | number} [user] The user ID for which the package is installed.
* The `current` user id is used by default.
* @returns {Promise<boolean>}
*/
export async function mobileIsAppInstalled(opts) {
const {appId, user} = requireArgs('appId', opts);
export async function mobileIsAppInstalled(appId, user) {
const _opts = {};
if (util.hasValue(user)) {
_opts.user = `${user}`;
Expand All @@ -47,7 +47,7 @@ export async function mobileIsAppInstalled(opts) {

/**
* @this {AndroidDriver}
* @param {string} appId
* @param {string} appId Application package identifier
* @returns {Promise<import('./types').AppState>}
*/
export async function queryAppState(appId) {
Expand All @@ -69,33 +69,13 @@ export async function queryAppState(appId) {

/**
* @this {AndroidDriver}
* @param {import('./types').QueryAppStateOpts} opts
* @returns {Promise<import('./types').AppState>}
*/
export async function mobileQueryAppState(opts) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, ok. like this method is a thin wrapper, so drivers will map with this.queryAppState

const {appId} = requireArgs('appId', opts);
return await this.queryAppState(appId);
}

/**
* @this {AndroidDriver}
* @param {string} appId
* @param {string} appId Application package identifier
* @returns {Promise<void>}
*/
export async function activateApp(appId) {
return await this.adb.activateApp(appId);
}

/**
* @this {AndroidDriver}
* @param {import('./types').ActivateAppOpts} opts
* @returns {Promise<void>}
*/
export async function mobileActivateApp(opts) {
const {appId} = requireArgs('appId', opts);
return await this.adb.activateApp(appId);
}

/**
* @this {AndroidDriver}
* @param {string} appId
Expand All @@ -108,18 +88,27 @@ export async function removeApp(appId, opts = {}) {

/**
* @this {import('../driver').AndroidDriver}
* @param {import('./types').RemoveAppOpts} opts
* @param {string} appId Application package identifier
* @param {number} [timeout] The count of milliseconds to wait until the
* app is uninstalled.
* @param {boolean} [keepData] Set to true in order to keep the
* application data and cache folders after uninstall.
* @param {boolean} [skipInstallCheck] Whether to check if the app is installed prior to
* uninstalling it. By default this is checked.
* @returns {Promise<boolean>}
*/
export async function mobileRemoveApp(opts) {
const {appId} = requireArgs('appId', opts);
return await this.removeApp(appId, opts);
export async function mobileRemoveApp(appId, timeout, keepData, skipInstallCheck) {
return await this.removeApp(appId, {
timeout,
keepData,
skipInstallCheck,
});
}

/**
* @this {AndroidDriver}
* @param {string} appId
* @param {Omit<import('./types').TerminateAppOpts, 'appId'>} [options={}]
* @param {import('./types').TerminateAppOpts} [options={}]
* @returns {Promise<boolean>}
*/
export async function terminateApp(appId, options = {}) {
Expand Down Expand Up @@ -180,12 +169,15 @@ export async function terminateApp(appId, options = {}) {

/**
* @this {AndroidDriver}
* @param {import('./types').TerminateAppOpts} opts
* @param {string} appId Application package identifier
* @param {number|string} [timeout] The count of milliseconds to wait until the app is terminated.
* 500ms by default.
* @returns {Promise<boolean>}
*/
export async function mobileTerminateApp(opts) {
const {appId} = requireArgs('appId', opts);
return await this.terminateApp(appId, opts);
export async function mobileTerminateApp(appId, timeout) {
return await this.terminateApp(appId, {
timeout,
});
}

/**
Expand All @@ -201,14 +193,49 @@ export async function installApp(appPath, opts) {

/**
* @this {AndroidDriver}
* @param {import('./types').InstallAppOpts} opts
* @param {string} appPath
* @param {boolean} [checkVersion]
* @param {number} [timeout] The count of milliseconds to wait until the app is installed.
* 20000ms by default.
* @param {boolean} [allowTestPackages] Set to true in order to allow test packages installation.
* `false` by default.
* @param {boolean} [useSdcard] Set to true to install the app on sdcard instead of the device memory.
* `false` by default.
* @param {boolean} [grantPermissions] Set to true in order to grant all the
* permissions requested in the application's manifest automatically after the installation is completed
* under Android 6+. `false` by default.
* @param {boolean} [replace] Set it to false if you don't want the application to be upgraded/reinstalled
* if it is already present on the device. `true` by default.
* @param {boolean} [noIncremental] Forcefully disables incremental installs if set to `true`.
* Read https://developer.android.com/preview/features#incremental for more details.
* `false` by default.
* @returns {Promise<void>}
*/
export async function mobileInstallApp(opts) {
const {appPath, checkVersion} = requireArgs('appPath', opts);
export async function mobileInstallApp(
appPath,
checkVersion,
timeout,
allowTestPackages,
useSdcard,
grantPermissions,
replace,
noIncremental,
) {
const opts = {
timeout,
allowTestPackages,
useSdcard,
grantPermissions,
replace,
noIncremental,
};
if (checkVersion) {
const localPath = await this.helpers.configureApp(appPath, APP_EXTENSIONS);
await this.adb.installOrUpgrade(localPath, null, Object.assign({}, opts, {enforceCurrentBuild: false}));
await this.adb.installOrUpgrade(localPath, null, Object.assign({}, {
appPath,
checkVersion,
...opts,
}, {enforceCurrentBuild: false}));
return;
}

Expand All @@ -217,11 +244,10 @@ export async function mobileInstallApp(opts) {

/**
* @this {AndroidDriver}
* @param {import('./types').ClearAppOpts} opts
* @param {string} appId Application package identifier
* @returns {Promise<void>}
*/
export async function mobileClearApp(opts) {
const {appId} = requireArgs('appId', opts);
export async function mobileClearApp(appId) {
await this.adb.clear(appId);
}

Expand Down
18 changes: 10 additions & 8 deletions lib/commands/appearance.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import {requireArgs} from '../utils';

const RESPONSE_PATTERN = /:\s+(\w+)/;

/**
* Set the Ui appearance.
*
* @since Android 10
* @this {import('../driver').AndroidDriver}
* @property {import('./types').SetUiModeOpts}
* @param {string} mode The UI mode to set the value for.
* Supported values are: 'night' and 'car'
* @param {string} value The actual mode value to set.
* Supported value for different UI modes are:
* - night: yes|no|auto|custom_schedule|custom_bedtime
* - car: yes|no
* @returns {Promise<void>}
*/
export async function mobileSetUiMode(opts) {
const {mode, value} = requireArgs(['mode', 'value'], opts);
export async function mobileSetUiMode(mode, value) {
await this.adb.shell(['cmd', 'uimode', mode, value]);
}

Expand All @@ -20,12 +22,12 @@ export async function mobileSetUiMode(opts) {
*
* @since Android 10
* @this {import('../driver').AndroidDriver}
* @property {import('./types').GetUiModeOpts}
* @param {string} mode The UI mode to set the value for.
* Supported values are: 'night' and 'car'
* @returns {Promise<string>} The actual state for the queried UI mode,
* for example 'yes' or 'no'
*/
export async function mobileGetUiMode(opts) {
const {mode} = requireArgs(['mode'], opts);
export async function mobileGetUiMode(mode) {
const response = await this.adb.shell(['cmd', 'uimode', mode]);
// response looks like 'Night mode: no'
const match = RESPONSE_PATTERN.exec(response);
Expand Down
5 changes: 2 additions & 3 deletions lib/commands/bluetooth.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ const SUPPORTED_ACTIONS = /** @type {const} */ ({
* Performs the requested action on the default bluetooth adapter
*
* @this {AndroidDriver}
* @param {import('./types').BluetoothOptions} opts
* @param {'enable' | 'disable' | 'unpairAll'} action
* @returns {Promise<void>}
* @throws {Error} if the device under test has no default bluetooth adapter
* or there was a failure while performing the action.
*/
export async function mobileBluetooth(opts) {
const {action} = opts;
export async function mobileBluetooth(action) {
switch (action) {
case SUPPORTED_ACTIONS.ENABLE:
await this.settingsApp.setBluetoothState(true);
Expand Down
6 changes: 3 additions & 3 deletions lib/commands/context/exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ export async function setContext(name) {

/**
* @this {AndroidDriver}
* @param {any} [opts={}]
* @param {number} [waitForWebviewMs]
* @returns {Promise<import('../types').WebviewsMapping[]>}
*/
export async function mobileGetContexts(opts = {}) {
export async function mobileGetContexts(waitForWebviewMs) {
const _opts = {
androidDeviceSocket: this.opts.androidDeviceSocket,
ensureWebviewsHavePages: true,
webviewDevtoolsPort: this.opts.webviewDevtoolsPort,
enableWebviewDetailsCollection: true,
waitForWebviewMs: opts.waitForWebviewMs || 0,
waitForWebviewMs: waitForWebviewMs || 0,
};
return await getWebViewsMapping.bind(this)(_opts);
}
Expand Down
Loading