Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into AND-50867_Update_co…
Browse files Browse the repository at this point in the history
…mpose_to_1_5
  • Loading branch information
pr4bh4sh committed Feb 2, 2024
2 parents 4d499fb + b167e1d commit 252d155
Show file tree
Hide file tree
Showing 14 changed files with 712 additions and 705 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## [2.34.1](https://github.com/appium/appium-espresso-driver/compare/v2.34.0...v2.34.1) (2024-01-26)


### Bug Fixes

* createADB ([#974](https://github.com/appium/appium-espresso-driver/issues/974)) ([5b5376e](https://github.com/appium/appium-espresso-driver/commit/5b5376ed0dd2e845953b189e5dbc0dc82709e7a2))

## [2.34.0](https://github.com/appium/appium-espresso-driver/compare/v2.33.2...v2.34.0) (2024-01-26)


### Features

* Bump appium-android-driver ([#973](https://github.com/appium/appium-espresso-driver/issues/973)) ([21a88cb](https://github.com/appium/appium-espresso-driver/commit/21a88cb2916beb72d023cbcfd227698982718f56))

## [2.33.2](https://github.com/appium/appium-espresso-driver/compare/v2.33.1...v2.33.2) (2024-01-16)


Expand Down
109 changes: 109 additions & 0 deletions lib/commands/app-management.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { errors } from 'appium/driver';
import { qualifyActivityName, requireOptions } from '../utils';

/**
* @this {import('../driver').EspressoDriver}
*/
// eslint-disable-next-line require-await
export async function launchApp () {
throw new errors.UnsupportedOperationError(
'Please create a new session in order to launch the application under test'
);
}

/**
* @typedef {Object} BackgroundAppOptions
* @property {number} [seconds] The amount of seconds to wait between putting the app to background and restoring it.
* Any negative value means to not restore the app after putting it to the background (the default behavior).
*/

/**
* Puts the app under test to the background
* and then restores it (if needed). The call is blocking is the
* app needs to be restored afterwards.
*
* @this {import('../driver').EspressoDriver}
* @param {BackgroundAppOptions} [opts={}]
*/
export async function mobileBackgroundApp (opts = {}) {
const {seconds = -1} = opts;
return await this.background(seconds);

Check failure on line 30 in lib/commands/app-management.js

View workflow job for this annotation

GitHub Actions / kotlin_test

The 'this' context of type 'EspressoDriver' is not assignable to method's 'this' of type 'AndroidDriver'.

Check failure on line 30 in lib/commands/app-management.js

View workflow job for this annotation

GitHub Actions / node_test (20)

The 'this' context of type 'EspressoDriver' is not assignable to method's 'this' of type 'AndroidDriver'.

Check failure on line 30 in lib/commands/app-management.js

View workflow job for this annotation

GitHub Actions / node_test (18)

The 'this' context of type 'EspressoDriver' is not assignable to method's 'this' of type 'AndroidDriver'.

Check failure on line 30 in lib/commands/app-management.js

View workflow job for this annotation

GitHub Actions / node_test (16)

The 'this' context of type 'EspressoDriver' is not assignable to method's 'this' of type 'AndroidDriver'.
}

/**
* @this {import('../driver').EspressoDriver}
*/
// eslint-disable-next-line require-await
export async function closeApp () {
throw new errors.UnsupportedOperationError(
'Please quit the session in order to close the application under test'
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
// eslint-disable-next-line require-await
export async function reset () {
throw new errors.UnsupportedOperationError(
'Please quit the session and create a new one ' +
'in order to close and launch the application under test');
}

/**
* @typedef {Object} StartActivityOptions
* @property {string} appActivity
* @property {string} [locale]
* @property {string} [optionalIntentArguments]
* @property {string} [optionalActivityArguments]
*/

/**
* Starts the given activity with intent options, activity options and locale.
* Activity could only be executed in scope of the current app package.
*
* @this {import('../driver').EspressoDriver}
* @param {StartActivityOptions} opts
* @returns {Promise<string>}
*/
export async function mobileStartActivity (opts) {
const appPackage = this.caps.appPackage;
const {
appActivity,
locale,
optionalIntentArguments,
optionalActivityArguments
} = requireOptions(opts, ['appActivity']);
return /** @type {string} */ (await this.espresso.jwproxy.command(`/appium/device/start_activity`, 'POST', {
appPackage,
appActivity,
locale,
optionalIntentArguments,
optionalActivityArguments
}));
}

/**
*
* @this {import('../driver').EspressoDriver}
* @param {string} appPackage
* @param {string} appActivity
* @param {string} appWaitPackage
* @param {string} appWaitActivity
*/
export async function startActivity (
appPackage, appActivity, appWaitPackage, appWaitActivity
) {
// intentAction, intentCategory, intentFlags, optionalIntentArguments, dontStopAppOnReset
// parameters are not supported by Espresso
const pkg = /** @type {string} */ (appPackage || this.caps.appPackage);
const appWaitPkg = /** @type {string} */ (appWaitPackage || pkg);
const appAct = qualifyActivityName(appActivity, pkg);
const appWaitAct = qualifyActivityName(appWaitActivity || appAct, appWaitPkg);
this.log.debug(`Starting activity '${appActivity}' for package '${appPackage}'`);
await this.espresso.jwproxy.command(`/appium/device/start_activity`, 'POST', {
appPackage: pkg,
appActivity: appAct,
});
await this.adb.waitForActivity(appWaitPkg, appWaitAct);
};
34 changes: 34 additions & 0 deletions lib/commands/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { requireOptions } from '../utils';

/**
* Stop proxying to any Chromedriver and redirect to Espresso
*
* @this {import('../driver').EspressoDriver}
* @returns {void}
*/
export function suspendChromedriverProxy () {
this.chromedriver = undefined;
this.proxyReqRes = this.espresso.proxyReqRes.bind(this.espresso);
this.proxyCommand = this.espresso.proxyCommand.bind(this.espresso);
this.jwpProxyActive = true;
}

/**
* Runs a chain of Espresso web atoms (see https://developer.android.com/training/testing/espresso/web for reference)
*
* Takes JSON of the form
*
* {
* "webviewEl": "<ELEMENT_ID>", // optional webview element to operate on
* "forceJavascriptEnabled": true|false, // if webview disables javascript, webatoms won't work, this forces it
* "methodChain": [
* {"name": "methodName", "atom": {"name": "atomName", "args": ["arg1", "arg2", ...]}},
* ...
* ]
* }
* @this {import('../driver').EspressoDriver}
*/
export async function mobileWebAtoms (opts = {}) {
opts = requireOptions(opts, ['methodChain']);
return await this.espresso.jwproxy.command(`/appium/execute_mobile/web_atoms`, 'POST', opts);
}
203 changes: 203 additions & 0 deletions lib/commands/element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import _ from 'lodash';
import { errors } from 'appium/driver';
import { util } from 'appium/support';
import { requireOptions } from '../utils';

/**
* Flash the element with given id.
* durationMillis and repeatCount are optional
* @this {import('../driver').EspressoDriver}
*/
export async function mobileFlashElement (opts = {}) {
const {durationMillis, repeatCount} = opts;
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/flash`,
'POST', {
durationMillis,
repeatCount
}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileDismissAutofill (opts = {}) {
await this.espresso.jwproxy.command(
`/session/:sessionId/appium/execute_mobile/${requireElementId(opts)}/dismiss_autofill`,
'POST',
{}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileSwipe (opts = {}) {
const {direction, swiper, startCoordinates, endCoordinates, precisionDescriber} = opts;
const element = requireElementId(opts);
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${element}/swipe`,
'POST',
{
direction,
element,
swiper,
startCoordinates,
endCoordinates,
precisionDescriber,
}
);
}


/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileOpenDrawer (opts = {}) {
const {gravity} = opts;
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/open_drawer`,
'POST',
{gravity}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileCloseDrawer (opts = {}) {
const {gravity} = opts;
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/close_drawer`,
'POST',
{gravity}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileSetDate (opts = {}) {
const {year, monthOfYear, dayOfMonth} = requireOptions(
opts, ['year', 'monthOfYear', 'dayOfMonth']
);
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/set_date`,
'POST', {
year,
monthOfYear,
dayOfMonth,
}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileSetTime (opts = {}) {
const {hours, minutes} = requireOptions(opts, ['hours', 'minutes']);
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/set_time`,
'POST', {
hours,
minutes,
}
);
}

/**
* @this {import('../driver').EspressoDriver}
*/
export async function mobileNavigateTo (opts = {}) {
const {menuItemId} = requireOptions(opts, ['menuItemId']);
const menuItemIdAsNumber = parseInt(menuItemId, 10);
if (_.isNaN(menuItemIdAsNumber) || menuItemIdAsNumber < 0) {
throw new errors.InvalidArgumentError(
`'menuItemId' must be a non-negative number. Found ${menuItemId}`
);
}
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/navigate_to`,
'POST',
{menuItemId}
);
}

/**
* Perform a 'GeneralClickAction' (https://developer.android.com/reference/androidx/test/espresso/action/GeneralClickAction)
* @this {import('../driver').EspressoDriver}
*/
export async function mobileClickAction (opts = {}) {
const {
tapper, coordinatesProvider, precisionDescriber, inputDevice, buttonState
} = opts;
return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/click_action`,
'POST', {
tapper, coordinatesProvider, precisionDescriber, inputDevice, buttonState
}
);
}

/**
*
* @this {import('../driver').EspressoDriver}
*/
export async function mobileScrollToPage (opts = {}) {
const {scrollTo, scrollToPage, smoothScroll} = opts;
const scrollToTypes = ['first', 'last', 'left', 'right'];
if (!scrollToTypes.includes(scrollTo)) {
throw new errors.InvalidArgumentError(
`"scrollTo" must be one of "${scrollToTypes.join(', ')}" found '${scrollTo}'`
);
}
if (!_.isInteger(scrollToPage) || scrollToPage < 0) {
throw new errors.InvalidArgumentError(
`"scrollToPage" must be a non-negative integer. Found '${scrollToPage}'`
);
}
if (util.hasValue(scrollTo) && util.hasValue(scrollToPage)) {
this.log.warn(`'scrollTo' and 'scrollToPage' where both provided. Defaulting to 'scrollTo'`);
}

return await this.espresso.jwproxy.command(
`/appium/execute_mobile/${requireElementId(opts)}/scroll_to_page`,
'POST', {
scrollTo,
scrollToPage,
smoothScroll,
}
);
}

/**
* @typedef {Object} PerformEditorActionOpts
* @property {string|number} action
*/

/**
* @this {import('../driver').EspressoDriver}
* @param {PerformEditorActionOpts} opts
* @returns {Promise<void>}
*/
export async function mobilePerformEditorAction (opts) {
const {action} = requireOptions(opts, ['action']);
await this.espresso.jwproxy.command('/appium/device/perform_editor_action', 'POST', {action});
}

// #region Internal Helpers

/**
* @param {Record<string, any>} opts
* @returns {string}
*/
function requireElementId (opts) {
const {element, elementId} = opts;
if (!element && !elementId) {
throw new errors.InvalidArgumentError('Element Id must be provided');
}
return util.unwrapElement(elementId || element);
}

// #endregion
8 changes: 2 additions & 6 deletions lib/commands/execute.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import _ from 'lodash';
import { errors } from 'appium/driver';

const extensions = {};

/**
* @this {import('../driver').EspressoDriver}
* @param {string} mobileCommand
* @param {Record<string, any>} [opts={}]
* @returns {Promise<any>}
*/
extensions.executeMobile = async function executeMobile (mobileCommand, opts = {}) {
export async function executeMobile (mobileCommand, opts = {}) {
const mobileCommandsMapping = {
shell: 'mobileShell',

Expand Down Expand Up @@ -130,6 +128,4 @@ extensions.executeMobile = async function executeMobile (mobileCommand, opts = {
`Only ${_.keys(mobileCommandsMapping)} commands are supported.`);
}
return await this[mobileCommandsMapping[mobileCommand]](opts);
};

export default extensions;
}
Loading

0 comments on commit 252d155

Please sign in to comment.